Heatmap of significant genes per cluster

Load data and libraries

##################
# LOAD LIBRARIES #
##################
library(tidyverse)
library(Seurat)
library(SeuratObject)
library(tidyseurat)
library(cowplot)
library(patchwork)
library(openxlsx)

source("../../bin/spatial_visualization.R")
source("../../bin/plotting_functions.R")

#########
# PATHS #
#########
input_dir <- "../../results/06_DGE_condition_st_data/"
result_dir <- "./Figures/02&03/"
if( isFALSE(dir.exists(result_dir)) ) { dir.create(result_dir,recursive = TRUE) }
epi_clus <- "^5$|^6$|^7|^8" # res 0.75
# epi_clus <- "^11$|^6$|^7|^9" # res 1.0

ord <- c("Superficial", "Upper IM", "Lower IM", "Basal","1","4","0","3","2","9","10","11","12")
ord1 <- c("5", "6", "7", "8","1","4","0","3","2","9","10","11","12")
sample_id <- c("P020", "P045", "P050", "P057",
               "P008", "P031", "P080", "P044", "P026", "P105", 
               "P001", "P004", "P014", "P018", "P087", "P118",
               "P021", "P024", "P067", "P081", "P117" ) %>% set_names()

#############
# LOAD DATA #
#############
DATA <- readRDS(paste0("../../results/03_clustering_st_data/","seuratObj_clustered.RDS"))
DEGs_table <- read_csv(paste0(input_dir,"DGEs_condition_wilcox.0.7.csv"))
pseudo_DEGs <- readRDS(paste0(input_dir,"Pseudobulk_across_DEGs.RDS"))
D <- DEGs_table %>%
  filter(., p_val_adj < 0.05) %>%
  #filter(., !(grepl("0|^3|9|10|11|12", .$subgroup))) %>%
  filter(., cluster == "L4") %>%
  mutate(sp_annot = ifelse(grepl("\\d", .$layers), "SubMuc", "epi")) %>%
  split(~sp_annot) 

venn-diagram of DEGs between DEA methods

##########################
# COMPUTE STATS FOR DEGs #
##########################
# Find intersections for each layer
int.fun <- function(df){
  g_lists <- df %>% # g_lists <- DEGs_nest$data[[1]] %>%
    filter(p_val_adj < 0.05) %>%
    split(~comb) %>%
    map(., ~pull(.x, "gene"))
  
  int <- Reduce(intersect, g_lists )
  return(int)
}

DEGs_nest <- DEGs_table %>%
  filter(!(grepl("11|$^12$", .$layers))) %>%
  arrange(layers) %>%
  filter(p_val_adj < 0.05) %>% 
  nest(data = -c("comb", "layers")) %>%
  mutate(#UP = map_int(data, ~ nrow(filter(.x, p_val_adj <= 0.05 & avg_log2FC > 0))),
         #DOWN = map_int(data, ~ nrow(filter(.x, p_val_adj <= 0.05 & avg_log2FC < 0))),
         n = map_int(data, ~ nrow(.x)) ) %>%
  select(-data) %>%
  pivot_wider(., names_from = comb, values_from = n)

comp <- unique(DEGs_table$comb)
DEGs_nest <- DEGs_table %>%
  filter(!(grepl("11|$^12$", .$layers))) %>%
  arrange(layers) %>%
  #filter(p_val_adj < 0.05) %>% 
  filter(p_val < 0.001) %>% 
  #group_by(Regulation) %>%
  nest(data = -layers) %>%
  mutate(pval.0.001 = map_int(data, ~ nrow(filter(.x, p_val <= 0.001))),
         FDR.0.05 = map_int(data, ~ nrow(filter(.x, p_val_adj <= 0.05))),
         UP = map_int(data, ~ nrow(filter(.x, p_val_adj <= 0.05 & avg_log2FC > 0))),
         DOWN = map_int(data, ~ nrow(filter(.x, p_val_adj <= 0.05 & avg_log2FC < 0)))) %>%
  left_join(., DEGs_nest) #%>%
  #mutate(intersection = map(data, ~int.fun(.x)))

DEGs_nest
## # A tibble: 11 × 12
##    layers      data     pval.0.001 FDR.0.05    UP  DOWN `L1-L2` `L1-L3` `L1-L4`
##    <chr>       <list>        <int>    <int> <int> <int>   <int>   <int>   <int>
##  1 0           <tibble>       2538      483   216   267      48      59      66
##  2 1           <tibble>       5147     1247   395   852     130     109     323
##  3 10          <tibble>       3226      618   187   431      98     105     193
##  4 2           <tibble>       6616     1509   245  1264      80      87     455
##  5 3           <tibble>       1736      371   144   227      40      35      38
##  6 4           <tibble>       7151     1548   264  1284      62     108     549
##  7 9           <tibble>       1604      262   105   157      55      40      56
##  8 Basal       <tibble>      12810     2910   185  2725      54      83    1172
##  9 Lower IM    <tibble>       7273     1176   174  1002      78      58     216
## 10 Superficial <tibble>       2017      546   238   308     115      74     143
## 11 Upper IM    <tibble>       2657      539   185   354      55      61     119
## # ℹ 3 more variables: `L2-L3` <int>, `L2-L4` <int>, `L3-L4` <int>
# Number of DEGs
WILK <- DEGs_table %>%
  filter(!(grepl("^11$|$^12$", .$layers))) %>%
  filter(p_val_adj < 0.05) %>% .$gene %>% unique()

PAIR <- pseudo_DEGs %>%
  select(layers, pairwise) %>% unnest(cols = c(pairwise)) %>% filter(FDR < 0.05) %>% .$Genes %>% unique()

ACK <- pseudo_DEGs %>%
  select(layers, across) %>% unnest(cols = c(across)) %>% filter(FDR < 0.05) %>% .$symbol %>% unique()

# setdiff(PAIR, WILK)
# intersect(intersect(PAIR, WILK), ACK)

all_DEGs <- c(PAIR, WILK, ACK) %>% unique()

#####################
# PLOT VENN DIAGRAM #
#####################
library(RColorBrewer)
myCol <- brewer.pal(3, "Pastel2")
myCol <- rep("#FFFFFF", 3)

# Chart
library(VennDiagram)
venn <- venn.diagram(
        x = list(WILK, PAIR, ACK),
        category.names = c("Wilcox" , "Pairwise" , "Across"),
        filename = './Figures/02&03/venn_diagramm.png',
        output=FALSE,
        
        # Output features
        imagetype="tiff" ,
        height = 480 , 
        width = 480 , 
        resolution = 300,
        compression = "lzw",
        
        # Circles
        lwd = .3,
        lty = 'solid',
        fill = myCol,
        
        # Numbers
        cex = .65,
        fontface = "plain",
        fontfamily = "sans",
        
        # Set names
        cat.cex = 0.7,
        cat.fontface = "plain",
        cat.default.pos = "outer",
        cat.pos = c(-33, 33, 180),
        cat.dist = c(0.095, 0.105, 0.05),
        cat.fontfamily = "sans",
        margin = c(.06), #unit(c(-2.5, -1, -2, -1), "lines")
        rotation = 1
)
p <- ggdraw() + draw_image("./venn_diagramm.png")
plot_grid(p, labels = c("A"))

#########################
# FACET COLOUR FUNCTION #
#########################
modify_facet_appearance <- function(plot = NULL,
                                    strip.background.x.fill = NULL, 
                                    strip.background.y.fill = NULL,
                                    strip.background.x.col = NULL,
                                    strip.background.y.col = NULL,
                                    strip.text.x.col = NULL,
                                    strip.text.y.col = NULL){
  
  if(is.null(plot)){stop("A ggplot (gg class) needs to be provided!")}
  
  # Generate gtable object to modify the facet strips:
  #g <- ggplot_gtable(ggplot_build(plot))
  #g <- ggplotGrob(plot)
  g <- as_gtable(plot)
  
  # Get the locations of the right and top facets in g:
  stripy <- which(grepl('strip-r|strip-l', g$layout$name)) # account for when strip positions are switched r-l and/or t-b in facet_grid(switch = )
  stripx <- which(grepl('strip-t|strip-b', g$layout$name))
  
  # Check that the provided value arrays have the same length as strips the plot has:
  lx <- c(length(strip.background.x.fill), length(strip.background.x.col), length(strip.text.x.col))
  if(!all(lx==length(stripx) | lx==0)){stop("The provided vectors with values need to have the same length and the number of facets in the plot!")}
  ly <- c(length(strip.background.y.fill), length(strip.background.y.col), length(strip.text.y.col))
  if(!all(ly==length(stripy) | ly==0)){stop("The provided vectors with values need to have the same length and the number of facets in the plot!")}
  
  # Change the strips on the y axis:
  for (i in seq_along(stripy)){ # if no strips in the right, the loop will not be executed as seq_along(stripy) will be integer(0)
    
    # Change strip fill and (border) colour :
    j1 <- which(grepl('strip.background.y', g$grobs[[stripy[i]]]$grobs[[1]]$childrenOrder))
    if(!is.null(strip.background.y.fill[i])){g$grobs[[stripy[i]]]$grobs[[1]]$children[[j1]]$gp$fill <- strip.background.y.fill[i]} # fill
    if(!is.null(strip.background.y.col[i])){g$grobs[[stripy[i]]]$grobs[[1]]$children[[j1]]$gp$col <- strip.background.y.col[i]} # border colour
    
    # Change color of text:
    j2 <- which(grepl('strip.text.y', g$grobs[[stripy[i]]]$grobs[[1]]$childrenOrder))
    if(!is.null(strip.text.y.col[i])){g$grobs[[stripy[i]]]$grobs[[1]]$children[[j2]]$children[[1]]$gp$col <- strip.text.y.col[i]}

  }
  
  # Same but for the x axis:
  for (i in seq_along(stripx)){
    
    # Change strip fill and (border) colour :
    j1 <- which(grepl('strip.background.x', g$grobs[[stripx[i]]]$grobs[[1]]$childrenOrder))
    if(!is.null(strip.background.x.fill[i])){g$grobs[[stripx[i]]]$grobs[[1]]$children[[j1]]$gp$fill <- strip.background.x.fill[i]} # fill
    if(!is.null(strip.background.x.col[i])){g$grobs[[stripx[i]]]$grobs[[1]]$children[[j1]]$gp$col <- strip.background.x.col[i]} # border colour
    
    # Change color of text:
    j2 <- which(grepl('strip.text.x', g$grobs[[stripx[i]]]$grobs[[1]]$childrenOrder))
    if(!is.null(strip.text.x.col[i])){g$grobs[[stripx[i]]]$grobs[[1]]$children[[j2]]$children[[1]]$gp$col <- strip.text.x.col[i]}

  }
  
  return(g) 
  
  # Note that it returns a gtable object. This can be ploted with plot() or grid::draw.grid(). 
  # patchwork can handle the addition of such gtable to a layout with other ggplot objects, 
  # but be sure to use patchwork::wrap_ggplot_grob(g) for proper alignment of plots!
  # See: https://patchwork.data-imaginist.com/reference/wrap_ggplot_grob.html
  
}

#############################
# NUMBER OF SIGNIFICANT DEGS #
#############################
clus_col <- c("#E41A1C","#FF7F00","#C77CFF","#984EA3","#00A9FF","#377EB8","#CD9600","#7CAE00","#e0e067","#FF61CC","#FF9DA7","#999999","#A65628")
clus_col <- set_names(clus_col, ord)

c <- c("L1-L2", "L1-L3", "L2-L3", "L1-L4", "L2-L4", "L3-L4")
regx <- c("\\w", "\\d")
sum <- DEGs_table %>%
  filter(., p_val_adj < 0.05) %>%
  filter(., !(grepl("9|11|12", .$subgroup))) %>%
  mutate(sp_annot = ifelse(grepl("\\d", .$layers), "SubMuc", "epi")) %>%
  split(~sp_annot) %>%
  
  map(., ~ .x %>%
      summarise(genes = n(), .by = c("comb", "Regulation", "layers", "subgroup")) %>% 
      mutate(genes = ifelse(Regulation == "DOWN", -(.$genes), (.$genes))) %>%
      mutate(layers = factor(.$layers, levels = ord)) %>%
      #mutate(layers = factor(.$subgroup, levels = ord1)) %>%
      mutate(comb = factor(.$comb, levels = rev(c)))
)

# dev.new(width=5, height=4, noRStudioGD = TRUE) 
A <- imap(sum, ~ {ggplot(data = .x) +
  geom_col(aes(x = genes, y = comb, fill = Regulation)) +
  #coord_flip() + 
  scale_fill_manual(values = c("#78a0cb", "#f27843")) + #  breaks = c(-400, -200, 0)
  facet_grid(layers ~ .) + # , switch="y" switches the position of the cluster lables
  scale_x_continuous(position = "bottom", labels = abs) + 
  scale_y_discrete(position = "right") +
  theme_light() + ggtitle("Number of significant genes") +
  theme(axis.title = element_blank(),
        plot.title = element_text(hjust = .5, size = 10, vjust = -.3),
        legend.title = element_blank(),
        legend.position = "none",
        plot.margin = unit(c(0,.2,0,.2), "lines"),
        panel.border = element_blank())
  #if(.y == "SubMuc"){clus_lab <- theme(strip.text.y = element_text(angle = 0))}else{clus_lab <- NULL}
  #{if(.y == "SubMuc", add(theme(strip.text.y = element_text(angle = 0))) else .}
  } %>%
  # NB! when using modify facet, you cannot have some specific themes such has theme_minimal()
  modify_facet_appearance(strip.background.y.fill = clus_col[levels(.x$layers) %in% unique(as.character(.x$layers))])
)
grid::grid.draw(A$epi)

# ggsave("/DEGs.pdf", width = 5, height = 4)
#############
# TOP DEGs #
############
n = 40
top_df <- DEGs_table %>%
    #filter(grepl("L4", .$comb)) %>%
    filter(p_val_adj <= 0.05) %>%
    filter(., cluster == "L4") %>%
    filter(., !(grepl("0|^3|9|10|11|12", .$subgroup))) %>%
    mutate("Sig. in" = paste0(.$layers[cur_group_rows()], collapse = "|"), .by="gene") %>%
    {. ->> temp} %>%
    split(~Morphology) %>%
    imap(., ~ .x %>%
           nest(data = -comb) %>%
           #pmap(., ~mutate(..2, data =2) ))
      #mutate(., data = pmap(., ~slice_max(..2, order_by = tibble(p_val, abs(avg_log2FC)), n=n),  by="Regulation") ) %>%
      mutate(., data = pmap(., ~slice_max(..2, order_by = tibble(abs(avg_log2FC), p_val), n=n),  by="Regulation") ) %>%
      mutate(., data = pmap(., ~arrange(..2, desc(avg_log2FC)) )) %>%
      mutate(., data = set_names(data, .data[["comb"]])) ) %>%
        {. ->> temp} %>%
        #select(-comb) %>%
        #flatten(.) 
    map(., ~unnest(., data))



(genes_epi <- top_df$epi %>% distinct(gene, Regulation) %>% deframe() )
##    SPRR2G    S100A7    PABPC3    SPRR2E     KRT17    SPRR2D      SLPI       PI3 
##      "UP"      "UP"      "UP"      "UP"      "UP"      "UP"      "UP"      "UP" 
##    KRTDAP    SNHG25      KLK7      TGM3     PPDPF    IGFBP7    MT-ND3    MT-ND2 
##      "UP"      "UP"      "UP"      "UP"      "UP"    "DOWN"    "DOWN"    "DOWN" 
##    LGALS7    MT-CO1   UPK3BL1  MTRNR2L8    IGFBP5    CRISP3 MTRNR2L12      IGKC 
##    "DOWN"    "DOWN"    "DOWN"    "DOWN"    "DOWN"    "DOWN"    "DOWN"    "DOWN" 
##     IGLC2     IGHG4      IGKC     KRT6B  MIR205HG   MT-ATP8    MT-ND5     OLFM4 
##    "DOWN"      "UP"      "UP"      "UP"      "UP"    "DOWN"    "DOWN"    "DOWN" 
##      HPGD    SPRR1A      DKK1       FLG      YOD1      KRT2     IGHG1  HIST1H1C 
##    "DOWN"    "DOWN"    "DOWN"    "DOWN"    "DOWN"    "DOWN"      "UP"      "UP" 
##     IFI27     KRT16     ISG15      TFF3   ANKRD37    SPINK6    COL3A1   PLA2G4D 
##      "UP"      "UP"      "UP"      "UP"      "UP"      "UP"    "DOWN"    "DOWN" 
##     TXNIP     SFRP4     SPARC    COL1A2    COL1A1 
##    "DOWN"    "DOWN"    "DOWN"    "DOWN"    "DOWN"
(genes_SubMuc <- top_df$SubMuc %>% distinct(gene, Regulation) %>% deframe() )
##     S100A7     SPRR2E      KRT14       TFF3     S100A2     SPRR2D      IGHG4 
##       "UP"       "UP"       "UP"       "UP"       "UP"       "UP"       "UP" 
##       SLPI     KRTDAP        SFN     S100A8      KRT6C   MIR205HG      CCL21 
##       "UP"       "UP"       "UP"       "UP"       "UP"       "UP"       "UP" 
##      KRT15       LCN2     SPRR2A      FABP5      REV3L       IFI6      SFRP4 
##       "UP"       "UP"       "UP"       "UP"     "DOWN"     "DOWN"     "DOWN" 
##      PLPP3      IGLC2      IGHA2       FTH1    HLA-DRA        FTL      IGHA1 
##     "DOWN"     "DOWN"     "DOWN"       "UP"       "UP"       "UP"       "UP" 
##   HLA-DRB1      MUC5B       CST3     GOLGA4       ATRX        FTX KCNIP4-IT1 
##       "UP"       "UP"       "UP"     "DOWN"     "DOWN"     "DOWN"     "DOWN" 
##       TCF4    ANKRD12       IGF1    MT-ATP8     SPINK5   MIR99AHG       MEG3 
##     "DOWN"     "DOWN"     "DOWN"     "DOWN"     "DOWN"     "DOWN"     "DOWN" 
##  MTRNR2L12   KCNQ1OT1      IGHG1      WFDC2      KRT17       COMP   SERPINE2 
##     "DOWN"     "DOWN"       "UP"       "UP"       "UP"     "DOWN"     "DOWN" 
##      MMP11      SPARC     COL5A1      MXRA5     COL1A2     COL3A1     COL1A1 
##     "DOWN"     "DOWN"     "DOWN"     "DOWN"     "DOWN"     "DOWN"     "DOWN"
#####################
# DEGs BY FUNCTION #
#####################
genes_epi <- c(
  TGM3 = "Cell Structure & Function",
  KLK6 = "Cell Structure & Function",
  KLK7 = "Cell Structure & Function",
  KLK13 = "Cell Structure & Function",
  EPCAM = "Cell Structure & Function",
  #KRT6B = "Cell Structure & Function",
  #KRT16 = "Cell Structure & Function",
  KRT15 = "Cell Structure & Function",
  KRT19 = "Cell Structure & Function",
  KRT17 = "Cell Structure & Function",
  KRT2 = "Cell Structure & Function",
  FLG = "Cell Structure & Function",
  #DMKN = "Cell Structure & Function",
  SPRR2E = "Cell Structure & Function",
  SPRR2G = "Cell Structure & Function",
  MUC4 = "Cell Structure & Function",
  TFF3 = "Cell Structure & Function",
  LGALS7 = "Cell Structure & Function",
  OLFM4 = "Cell Structure & Function",
  SPINK6 = "Cell Structure & Function",
  LYPD2 = "Cell Structure & Function",
  
  STAT3 = "Immune",
  IL18 = "Immune",
  IGHG1 = "Immune",
  IGHG2 = "Immune",
  IGHA2 = "Immune",
  IGLC2 = "Immune",
  IGHG4 = "Immune",
  SH2D3A = "Immune",
  SLPI = "Immune",
  IFI27 = "Immune",
  ISG15 = "Immune",
  LY6D = "Immune",
  EPCAM = "Immune",
  
  CFD = "Immune",
  # GALNT5 = "Immune",
  # ITGB8 = "Cell Structure & Function",
  # SLCO2A1 = "Immune",
  PLA2G4D = "Immune",
  PI3 = "Immune",
  S100A7 = "Immune"
  # S100P = "Immune"
)

genes_SubMuc <- c(
  # Cell Structure & Function 
  TFF3 = "Cell Structure & Function",
  KRT17 = "Cell Structure & Function",
  KRT6C = "Cell Structure & Function",
  SPRR2E = "Cell Structure & Function",
  
  # MIR205HG = "Cell Structure & Function",
  COMP = "Cell Structure & Function",
  MMP11 = "Cell Structure & Function",
  SPARC = "Cell Structure & Function",
  MFAP5 = "Cell Structure & Function",
  #KCNQ1OT1 = "Other",
  COL1A1 = "Cell Structure & Function",
  COL3A1 = "Cell Structure & Function",
  COL27A1 = "Cell Structure & Function",
  #COL15A1 = "Cell Structure & Function",
  #COL14A1 = "Cell Structure & Function",
  TGFBR2 = "Cell Structure & Function",
  ZEB2 = "Cell Structure & Function",
  FAM25A = "Cell Structure & Function",
  CLCA4 = "Cell Structure & Function",
  # ANKRD36C = "Cell Structure & Function",
  PCP4 = "Cell Structure & Function",
  # KCNMA1 = "Cell Structure & Function",
  # RPS10 = "Cell Structure & Function",
  # AKAP9 = "Cell Structure & Function",
  OLFML3 = "Cell Structure & Function",
  ITGB8 = "Cell Structure & Function",

  # Immune-Related Genes
  NKTR = "Immune",
  # IRF2BP1 = "Immune",
  SLPI = "Immune",
  TCF4 = "Immune",
  "HLA-C" = "Immune",
  IGHG2 = "Immune",
  IGHG4 = "Immune",
  IGHA2 = "Immune",
  IGLC2 = "Immune",
  IGLC3 = "Immune",
  IFI6 = "Immune",
  CCL21 = "Immune",
  FABP5 = "Immune",
  #CYBC1 = "Immune",
  
  S100A7 = "Immune",
  S100A8 = "Immune",
  #S100A9 = "Immune",
  # PTGDS = "Immune",
  BDP1 = "Immune",
  VCAN = "Immune",
  FOXO3 = "Immune",
  AREL1 = "Immune"
)

#################
# PLOT FUNCTION #
#################
morf_DEGs_plot <- function(genes = genes_epi, clus="^5$|^6$|^7|^8"){
  df <- DATA %>%
    mutate(., FetchData(., vars = c(names(genes)), slot = "counts")) %>%
    filter(., grepl(clus, .$Clusters)) %>%
    as_tibble() %>%
    select(1:5, layers, all_of(names(genes))) %>%
    pivot_longer(cols = any_of(names(genes)), names_to = "gene", values_to = "values") %>%
    # filter(gene == "LGALS7") %>%
    group_by( groups, gene) %>%
    summarize(sum_counts = sum(values), .groups="drop") %>%
    mutate("Sum counts(log10)" = log10(.$sum_counts)) %>%
    arrange(`Sum counts(log10)`) %>%
    mutate(type = genes[.$gene])
  
  absmax <- function(x) { x[which.max( abs(x) )]}
  ord <<- df %>%
    #pivot_wider(id_cols = -`Sum counts(log10)`,names_from = "groups", values_from = "sum_counts") %>%
    pivot_wider(id_cols = -sum_counts, names_from = "groups", values_from = `Sum counts(log10)`) %>%
    mutate(diff_L1_L4 = L4-L1, 
           diff_L2_L4 = L4-L2, 
           diff_L3_L4 = L4-L3, .by = "gene") %>%
    rowwise() %>% 
    mutate(Regulation = sum(c_across(starts_with("diff")) ),
           max = paste0(names(.[3:6])[c_across(starts_with("L")) == absmax(c_across(starts_with("L")))], collapse = '_') ) %>%
    ungroup() %>%
    mutate(Regulation = ifelse(.$Regulation < 0, "DOWN", "UP"),
           max = str_extract(.$max, "L\\d"))
  
  m <- ifelse(clus == "^5$|^6$|^7|^8", "Epithelial", "Submucosal")
  write.xlsx(ord, paste0(result_dir, "Selected_DEGs_FIG2-3_", m, ".xlsx"))
  #####################
  # TOP DEGs PLOTTING #
  #####################
  g_ord <- arrange(ord, diff_L1_L4) %>% pull("gene") %>% unique()
  
  col <- c("L1"="#FF7F00", "L2"="#FED9A6", "L3"="#6A51A3", "L4"="#9E9AC8" ) # "#FFFFB3", "#BEBADA","#8DD3C7", "#FB8072",
  col <- c("L1"="#56B4E9","L2"="#009E73","L3"="#CC79A7", "L4"="#FC8D62")
  
  (B <- left_join(df, select(ord, Regulation, max, gene), by="gene") %>%
      #mutate(., gene = factor(gene, levels=g_ord)) %>%
      ggplot2::ggplot(data=., aes(x=fct_reorder2(gene, Regulation,`Sum counts(log10)`), y=`Sum counts(log10)`)) +
    geom_point(aes(col=groups), size = 2) +
    scale_colour_manual(values = col) +
    facet_grid(cols=vars(type), rows = vars(), scales = "free_x", space = "free_x") +
    #facet_wrap("max", ncol = 2, strip.position = "top", scales = "free_x", shrink = F) +
    theme_minimal() +
    theme(legend.position = "bottom",
          plot.margin = unit(c(5,-1,5,1),units = "pt"),
          legend.margin = margin(-15,2,-8,2), # moves the legend box
          legend.title = element_blank(),
          legend.text = element_text(size = 8),
          legend.spacing.x = unit(4, 'pt'),
          axis.title = element_text(size=8),
          axis.text.x = element_text(size=8, angle=45, hjust=1, color="black"),
          axis.title.x = element_blank(),
          #text = element_text(size = 10),
    ) )
}

(B_epi <- morf_DEGs_plot(genes = genes_epi))

(B_SubMuc <- morf_DEGs_plot(genes = genes_SubMuc, clus="^1$|^4$|^0|^3"))

#########################
# COMBINE PANEL A AND B #
#########################
# patchwork does not respect margins when nesting plots, use cowplot instead!
# dev.new(width=6.7, height=6.7, noRStudioGD = TRUE) 
(FIG2 <- plot_grid(A$epi, B_epi, ncol = 1, rel_heights = c(1), rel_widths = c(1), labels = c("A", "C")) )

# ggsave(paste0(result_dir, "FIG2.png"), FIG2,  width = 6.7, height = 6.7, bg = "white", dpi = 300)
#########################
# COMBINE PANEL A AND B #
#########################
# patchwork does not respect margins when nesting plots, use cowplot instead!
# dev.new(width=6.7, height=7.5, noRStudioGD = TRUE) 
(FIG3 <- plot_grid(A$SubMuc, B_SubMuc, ncol = 1, rel_heights = c(1, .7), rel_widths = c(1), labels = c("A", "B")) )

# ggsave(paste0(result_dir, "FIG3.png"), FIG3, width = 6.7, height = 7.5, bg = "white", dpi = 300)
ord <- c("Superficial", "Upper IM", "Lower IM", "Basal","1","4","0","3","2","9","10","11","12")
col <- set_names(c("#E41A1C","#FF7F00","#C77CFF","#984EA3","#00A9FF","#377EB8",
              "#CD9600","#7CAE00","#e0e067","#FF61CC","#FF9DA7","#999999","#A65628"), ord)
ID <- sample_id
col_gr <- c("L1"="#56B4E9","L2"="#009E73","L3"="#CC79A7", "L4"="#FC8D62")

layer_dotplot.fun <- function(DATA, feat, spatial_dist, 
                              facet = TRUE, 
                              line = "mean", 
                              x_max=NULL, 
                              morf="epi", clus="^5$|^6$|^7|^8"){
  DAT <- DATA %>%
    #filter(., grepl(morf, .$sp_annot)) %>%
    filter(., grepl(clus, .$Clusters)) %>%
    mutate(., FetchData(., vars = c(feat)) ) %>%
    select(orig.ident, groups, layers, all_of(c(feat)), {{spatial_dist}})
  
  if(morf=="epi"){probs <- c(0.179, 0.9025)}else{probs <- c(0.13, 0.78)}
  
    rects <- DAT %>%
    group_by(layers) %>%
    summarise(., ystart=min({{spatial_dist}}, na.rm=T), yend=max({{spatial_dist}}, na.rm=T),
              Q1=quantile({{spatial_dist}}, probs = probs[1], na.rm=T),
              Q3=quantile({{spatial_dist}}, probs = probs[2], na.rm=T)) %>%
    filter(!(is.infinite(.$ystart))) %>%
    mutate(Q1 = ifelse(.$Q1 == min(.$Q1), 0,.$Q1)) %>%
    mutate(Q3 = ifelse(.$Q3 == max(.$Q3), max(.$yend),.$Q3)) %>%
    mutate(Q1 = ifelse(.$layers == "4", .$Q1+10,.$Q1)) %>%
    mutate(Q1 = ifelse(.$layers == "0", .$Q1-.6,.$Q1)) %>%
    mutate(Q1 = ifelse(.$layers == "Lower IM", .$Q1-.7,.$Q1)) %>%
    mutate(Q3 = ifelse(.$layers == "Upper IM", .$Q3+.95,.$Q3)) %>%
    mutate(Q1 = ifelse(.$layers == "10", .$Q1+.5,.$Q1)) %>%
      {. ->> rect_df} %>%
    arrange(ystart) %>% ungroup()
        
    mean <- DAT %>%
      #group_by(groups, layers) %>%
      summarize(mean = mean(.data[[feat]]), median = median(.data[[feat]]), .by = c("groups", "layers")) %>%
      left_join(rects, mean, by = c("layers")) 

  if(facet == TRUE){facets <- facet_wrap(~groups, ncol = 2) }else{facets <- NULL}
  
  dot <- ggplot() +
    #ggtitle(feature) +
    geom_rect(data = rects, alpha = 0.1, show.legend=FALSE,
              aes(xmin = -Inf, xmax = Inf, ymin = Q1, ymax = Q3, fill = layers)) +
    geom_jitter(data = DAT, aes(x=.data[[feat]], y={{spatial_dist}}, col=layers), 
                width = 0.1, alpha = 0.7, size=.3) + 
    #geom_vline(data=mean, aes(xintercept=mean, col=layers)) +
    scale_fill_manual(values = col) + 
    scale_colour_manual(values = col) +
    {if(!(is.null(line))){
      list(ggnewscale::new_scale_color(),
      geom_segment(data=mean, aes(x=.data[[line]], y=Q1, xend=.data[[line]], yend=Q3, col=groups)),
      scale_colour_manual(values = col_gr)) 
      }} +
    # geom_smooth(data = filter(DAT, .data[[feat]] != 0), n=1000, aes(y={{spatial_dist}}, x=.data[[feat]], col=orig.ident)) + 
    guides(fill = guide_legend(override.aes = list(size=2), keyheight = .7, keywidth = .7)) +
    scale_y_reverse(expand = c(0, 0)) +
    #scale_x_continuous(expand = c(0, 0)) +
    {if(!(is.null(x_max))){xlim(-.5, x_max)}} +
    facets +
    my_theme + ylab("Similarity in gene expression") +
    theme(plot.margin = unit(c(0,.2,0,.2), "lines"),
          #legend.box.margin=margin(0,0,0,0),
          legend.margin=margin(0,0,0,-5),
          panel.spacing = unit(0, "cm"),
          panel.border = element_blank(),
          axis.line = element_line(),
          panel.grid.major = element_line(linewidth = 0.2),
          panel.grid.minor = element_line(linewidth = 0.1))
  return(dot)
}

#################################
# CLUS DOTPLOT PER SUBMUC LAYER #
#################################
# dev.new(height=1.9, width=6.7, noRStudioGD = TRUE)
# dev.new(height=3.2, width=3.54, noRStudioGD = TRUE) #with legend
feat <- c("KCNQ1OT1","FAM25A","CLCA4","IGHG2" )
dot_fig <- map(feat, 
               ~layer_dotplot.fun(DATA, .x, sp_dist_SubMuc, morf="SubMuc", clus="^1$|^4$|^0|^3",
                                  facet = F, line = "mean")) # , x_max = 6
dot_fig[[3]]
C_1 <- wrap_plots(dot_fig, ncol = 4, guides = "collect"  ) + 
  plot_layout(axis_titles = "collect") & 
  theme(#legend.position = c(.1, 1.15), legend.direction = "horizontal",
        plot.margin = unit(c(.2,0,0,.2), "lines"),
        legend.position = 'top', 
        legend.justification = "right", 
        legend.background = element_rect(colour ="gray", linewidth=.2),
        legend.margin=margin(1,2,1,1), # moves the legend box
        legend.box.margin=margin(1,1,-4,0), # moves the legend
        #legend.box.margin=margin(-30,0,-15,0), 
        # axis.title.y.left = element_text(margin = margin(r = 5))
        ) 

( C_1 <- plot_grid(C_1, NULL, rel_widths = c(1,.01)) )
# ggsave("./Figures/03/Fig_03C1.png", C_1, width = 6.7, height = 2.4) #, dpi = 300

#################################
# CLUS DOTPLOT PER EPI LAYER #
#################################
# dev.new(height=1.9, width=6.7, noRStudioGD = TRUE)
# dev.new(height=3.2, width=3.54, noRStudioGD = TRUE) #with legend
feat <- c("KRT17","IL18","STAT3","IGHG4" )
dot_fig <- map(feat, 
               ~layer_dotplot.fun(DATA, .x, facet = F, line = "mean", sp_dist_epi)) # , x_max = 6
dot_fig[[1]]
C_1 <- wrap_plots(dot_fig, ncol = 4, guides = "collect"  ) + 
  plot_layout(axis_titles = "collect") & 
  theme(#legend.position = c(.1, 1.15), legend.direction = "horizontal",
        plot.margin = unit(c(.2,0,0,.2), "lines"),
        legend.position = 'top', 
        legend.justification = "right", 
        legend.background = element_rect(colour ="gray", linewidth=.2),
        legend.margin=margin(1,2,1,1), # moves the legend box
        legend.box.margin=margin(1,1,-4,0), # moves the legend
        #legend.box.margin=margin(-30,0,-15,0), 
        # axis.title.y.left = element_text(margin = margin(r = 5))
        ) 

( C_1 <- plot_grid(C_1, NULL, rel_widths = c(1,.01)) )
ggsave("./Figures/03/Fig_03C1.png", C_1, width = 6.7, height = 2.4) #, dpi = 300
LS0tCnRpdGxlOiAiRmlndXJlIDIgJiAzIgpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZC0lbS0lWScpYCIKZm9ybWF0OgogIGh0bWw6CiAgICBlbWJlZC1yZXNvdXJjZXM6IHRydWUKICAgIGNvZGUtZm9sZDogc2hvdwpwYXJhbXM6CiAgZmlnLnBhdGg6ICJgciBwYXN0ZTAocGFyYW1zJGZpZy5wYXRoKWAiICMuL0ZpZ3VyZXMvCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogY29uc29sZQotLS0KIyMgSGVhdG1hcCBvZiBzaWduaWZpY2FudCBnZW5lcyBwZXIgY2x1c3RlcgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBmaWcud2lkdGggICAgID0gNi42OTI5MTMzODU4LAogIGZpZy5wYXRoICAgICAgPSBwYXJhbXMkZmlnLnBhdGgsIyIuLi9GaWd1cmVzLyIsCiAgZmlnLmFsaWduICAgICA9ICJjZW50ZXIiLAogIG1lc3NhZ2UgICAgICAgPSBGQUxTRSwKICB3YXJuaW5nICAgICAgID0gRkFMU0UsCiAgZGV2ICAgICAgICAgICA9IGMoInBuZyIpLAogIGRwaSAgICAgICAgICAgPSAzMDAsCiAgZmlnLnByb2Nlc3MgPSBmdW5jdGlvbihmaWxlbmFtZSl7CiAgICBuZXdfZmlsZW5hbWUgPC0gc3RyaW5ncjo6c3RyX3JlbW92ZShzdHJpbmcgPSBmaWxlbmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiLTEiKQogICAgZnM6OmZpbGVfbW92ZShwYXRoID0gZmlsZW5hbWUsIG5ld19wYXRoID0gbmV3X2ZpbGVuYW1lKQogICAgaWZlbHNlKGZzOjpmaWxlX2V4aXN0cyhuZXdfZmlsZW5hbWUpLCBuZXdfZmlsZW5hbWUsIGZpbGVuYW1lKQogIH0KICApCiMgIHNldHdkKCJ+L3dvcmsvQnJvbGlkZW5zX3dvcmsvUHJvamVjdHMvU3BhdGlhbF9NaWNyb2Jpb3RhL3NyYy9NYW51c2NyaXB0IikKYGBgCgpgYGB7ciBiYWNrZ3JvdW5kX2pvYiwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0Kc291cmNlKCIuLi8uLi9iaW4vcmVuZGVyX3dpdGhfam9icy5SIikKCiMgcXVhcnRvCiMgcmVuZGVyX2h0bWxfd2l0aF9qb2Iob3V0X2RpciA9IGxhYl9kaXIpCiMgZnM6OmZpbGVfbW92ZShwYXRoID0gZmlsZSwgbmV3X3BhdGggPSBwYXN0ZTAobGFiX2RpciwgZmlsZSkpCgojIGN1cnJlbnRseSB1c2luZyBxdWFydG8gZm9yIGdpdGh1YiBhbmQga25pdGVyIGZvciBodG1sIGR1ZSB0byBzb3VyY2UgY29kZSBvcHRpb24gCnJlbmRlcl9naXRfd2l0aF9qb2IoZmlnX3BhdGggPSAiLi9GaWd1cmVzLzAyJjAzLyIpCnN5c3RlbTIoY29tbWFuZCA9ICJzZWQiLCBzdGRvdXQgPSBUUlVFLAogICAgICAgIGFyZ3MgPSBjKCItaSIsICInJyIsIi1lIiwgJ3Mvc3JjPVxcIlxcLi9zcmM9XFwiXFwuXFwuL2cnLAogICAgICAgICAgICAgICAgIHBhc3RlMCgiLi9tZF9maWxlcy8iLCBiYXNlbmFtZSgiLi8wMiYwM19maWd1cmVzLm1kIikpKSkKCiMga25pdGVyCmtuaXRfaHRtbF93aXRoX2pvYihvdXRfZGlyID0gIi4uL2xhYl9ib29rL2ZpZ3VyZV8wMiYwMyIsIGZpZ19wYXRoID0gIi4vRmlndXJlcy8wMiYwMy8iKQpgYGAKCiMjIyBMb2FkIGRhdGEgYW5kIGxpYnJhcmllcwpgYGB7ciBMb2FkX2RhdGF9CiMjIyMjIyMjIyMjIyMjIyMjIwojIExPQUQgTElCUkFSSUVTICMKIyMjIyMjIyMjIyMjIyMjIyMjCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShTZXVyYXRPYmplY3QpCmxpYnJhcnkodGlkeXNldXJhdCkKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShvcGVueGxzeCkKCnNvdXJjZSgiLi4vLi4vYmluL3NwYXRpYWxfdmlzdWFsaXphdGlvbi5SIikKc291cmNlKCIuLi8uLi9iaW4vcGxvdHRpbmdfZnVuY3Rpb25zLlIiKQoKIyMjIyMjIyMjCiMgUEFUSFMgIwojIyMjIyMjIyMKaW5wdXRfZGlyIDwtICIuLi8uLi9yZXN1bHRzLzA2X0RHRV9jb25kaXRpb25fc3RfZGF0YS8iCnJlc3VsdF9kaXIgPC0gIi4vRmlndXJlcy8wMiYwMy8iCmlmKCBpc0ZBTFNFKGRpci5leGlzdHMocmVzdWx0X2RpcikpICkgeyBkaXIuY3JlYXRlKHJlc3VsdF9kaXIscmVjdXJzaXZlID0gVFJVRSkgfQplcGlfY2x1cyA8LSAiXjUkfF42JHxeN3xeOCIgIyByZXMgMC43NQojIGVwaV9jbHVzIDwtICJeMTEkfF42JHxeN3xeOSIgIyByZXMgMS4wCgpvcmQgPC0gYygiU3VwZXJmaWNpYWwiLCAiVXBwZXIgSU0iLCAiTG93ZXIgSU0iLCAiQmFzYWwiLCIxIiwiNCIsIjAiLCIzIiwiMiIsIjkiLCIxMCIsIjExIiwiMTIiKQpvcmQxIDwtIGMoIjUiLCAiNiIsICI3IiwgIjgiLCIxIiwiNCIsIjAiLCIzIiwiMiIsIjkiLCIxMCIsIjExIiwiMTIiKQpzYW1wbGVfaWQgPC0gYygiUDAyMCIsICJQMDQ1IiwgIlAwNTAiLCAiUDA1NyIsCiAgICAgICAgICAgICAgICJQMDA4IiwgIlAwMzEiLCAiUDA4MCIsICJQMDQ0IiwgIlAwMjYiLCAiUDEwNSIsIAogICAgICAgICAgICAgICAiUDAwMSIsICJQMDA0IiwgIlAwMTQiLCAiUDAxOCIsICJQMDg3IiwgIlAxMTgiLAogICAgICAgICAgICAgICAiUDAyMSIsICJQMDI0IiwgIlAwNjciLCAiUDA4MSIsICJQMTE3IiApICU+JSBzZXRfbmFtZXMoKQoKIyMjIyMjIyMjIyMjIwojIExPQUQgREFUQSAjCiMjIyMjIyMjIyMjIyMKREFUQSA8LSByZWFkUkRTKHBhc3RlMCgiLi4vLi4vcmVzdWx0cy8wM19jbHVzdGVyaW5nX3N0X2RhdGEvIiwic2V1cmF0T2JqX2NsdXN0ZXJlZC5SRFMiKSkKREVHc190YWJsZSA8LSByZWFkX2NzdihwYXN0ZTAoaW5wdXRfZGlyLCJER0VzX2NvbmRpdGlvbl93aWxjb3guMC43LmNzdiIpKQpwc2V1ZG9fREVHcyA8LSByZWFkUkRTKHBhc3RlMChpbnB1dF9kaXIsIlBzZXVkb2J1bGtfYWNyb3NzX0RFR3MuUkRTIikpCgpgYGAKCmBgYHtyfQpEIDwtIERFR3NfdGFibGUgJT4lCiAgZmlsdGVyKC4sIHBfdmFsX2FkaiA8IDAuMDUpICU+JQogICNmaWx0ZXIoLiwgIShncmVwbCgiMHxeM3w5fDEwfDExfDEyIiwgLiRzdWJncm91cCkpKSAlPiUKICBmaWx0ZXIoLiwgY2x1c3RlciA9PSAiTDQiKSAlPiUKICBtdXRhdGUoc3BfYW5ub3QgPSBpZmVsc2UoZ3JlcGwoIlxcZCIsIC4kbGF5ZXJzKSwgIlN1Yk11YyIsICJlcGkiKSkgJT4lCiAgc3BsaXQofnNwX2Fubm90KSAKYGBgCgojIyMgdmVubi1kaWFncmFtIG9mIERFR3MgYmV0d2VlbiBERUEgbWV0aG9kcwpgYGB7ciBWZW5uLWRpYWdyYW0tREVHc30KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBDT01QVVRFIFNUQVRTIEZPUiBERUdzICMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBGaW5kIGludGVyc2VjdGlvbnMgZm9yIGVhY2ggbGF5ZXIKaW50LmZ1biA8LSBmdW5jdGlvbihkZil7CiAgZ19saXN0cyA8LSBkZiAlPiUgIyBnX2xpc3RzIDwtIERFR3NfbmVzdCRkYXRhW1sxXV0gJT4lCiAgICBmaWx0ZXIocF92YWxfYWRqIDwgMC4wNSkgJT4lCiAgICBzcGxpdCh+Y29tYikgJT4lCiAgICBtYXAoLiwgfnB1bGwoLngsICJnZW5lIikpCiAgCiAgaW50IDwtIFJlZHVjZShpbnRlcnNlY3QsIGdfbGlzdHMgKQogIHJldHVybihpbnQpCn0KCkRFR3NfbmVzdCA8LSBERUdzX3RhYmxlICU+JQogIGZpbHRlcighKGdyZXBsKCIxMXwkXjEyJCIsIC4kbGF5ZXJzKSkpICU+JQogIGFycmFuZ2UobGF5ZXJzKSAlPiUKICBmaWx0ZXIocF92YWxfYWRqIDwgMC4wNSkgJT4lIAogIG5lc3QoZGF0YSA9IC1jKCJjb21iIiwgImxheWVycyIpKSAlPiUKICBtdXRhdGUoI1VQID0gbWFwX2ludChkYXRhLCB+IG5yb3coZmlsdGVyKC54LCBwX3ZhbF9hZGogPD0gMC4wNSAmIGF2Z19sb2cyRkMgPiAwKSkpLAogICAgICAgICAjRE9XTiA9IG1hcF9pbnQoZGF0YSwgfiBucm93KGZpbHRlcigueCwgcF92YWxfYWRqIDw9IDAuMDUgJiBhdmdfbG9nMkZDIDwgMCkpKSwKICAgICAgICAgbiA9IG1hcF9pbnQoZGF0YSwgfiBucm93KC54KSkgKSAlPiUKICBzZWxlY3QoLWRhdGEpICU+JQogIHBpdm90X3dpZGVyKC4sIG5hbWVzX2Zyb20gPSBjb21iLCB2YWx1ZXNfZnJvbSA9IG4pCgpjb21wIDwtIHVuaXF1ZShERUdzX3RhYmxlJGNvbWIpCkRFR3NfbmVzdCA8LSBERUdzX3RhYmxlICU+JQogIGZpbHRlcighKGdyZXBsKCIxMXwkXjEyJCIsIC4kbGF5ZXJzKSkpICU+JQogIGFycmFuZ2UobGF5ZXJzKSAlPiUKICAjZmlsdGVyKHBfdmFsX2FkaiA8IDAuMDUpICU+JSAKICBmaWx0ZXIocF92YWwgPCAwLjAwMSkgJT4lIAogICNncm91cF9ieShSZWd1bGF0aW9uKSAlPiUKICBuZXN0KGRhdGEgPSAtbGF5ZXJzKSAlPiUKICBtdXRhdGUocHZhbC4wLjAwMSA9IG1hcF9pbnQoZGF0YSwgfiBucm93KGZpbHRlcigueCwgcF92YWwgPD0gMC4wMDEpKSksCiAgICAgICAgIEZEUi4wLjA1ID0gbWFwX2ludChkYXRhLCB+IG5yb3coZmlsdGVyKC54LCBwX3ZhbF9hZGogPD0gMC4wNSkpKSwKICAgICAgICAgVVAgPSBtYXBfaW50KGRhdGEsIH4gbnJvdyhmaWx0ZXIoLngsIHBfdmFsX2FkaiA8PSAwLjA1ICYgYXZnX2xvZzJGQyA+IDApKSksCiAgICAgICAgIERPV04gPSBtYXBfaW50KGRhdGEsIH4gbnJvdyhmaWx0ZXIoLngsIHBfdmFsX2FkaiA8PSAwLjA1ICYgYXZnX2xvZzJGQyA8IDApKSkpICU+JQogIGxlZnRfam9pbiguLCBERUdzX25lc3QpICMlPiUKICAjbXV0YXRlKGludGVyc2VjdGlvbiA9IG1hcChkYXRhLCB+aW50LmZ1bigueCkpKQoKREVHc19uZXN0CgoKIyBOdW1iZXIgb2YgREVHcwpXSUxLIDwtIERFR3NfdGFibGUgJT4lCiAgZmlsdGVyKCEoZ3JlcGwoIl4xMSR8JF4xMiQiLCAuJGxheWVycykpKSAlPiUKICBmaWx0ZXIocF92YWxfYWRqIDwgMC4wNSkgJT4lIC4kZ2VuZSAlPiUgdW5pcXVlKCkKClBBSVIgPC0gcHNldWRvX0RFR3MgJT4lCiAgc2VsZWN0KGxheWVycywgcGFpcndpc2UpICU+JSB1bm5lc3QoY29scyA9IGMocGFpcndpc2UpKSAlPiUgZmlsdGVyKEZEUiA8IDAuMDUpICU+JSAuJEdlbmVzICU+JSB1bmlxdWUoKQoKQUNLIDwtIHBzZXVkb19ERUdzICU+JQogIHNlbGVjdChsYXllcnMsIGFjcm9zcykgJT4lIHVubmVzdChjb2xzID0gYyhhY3Jvc3MpKSAlPiUgZmlsdGVyKEZEUiA8IDAuMDUpICU+JSAuJHN5bWJvbCAlPiUgdW5pcXVlKCkKCiMgc2V0ZGlmZihQQUlSLCBXSUxLKQojIGludGVyc2VjdChpbnRlcnNlY3QoUEFJUiwgV0lMSyksIEFDSykKCmFsbF9ERUdzIDwtIGMoUEFJUiwgV0lMSywgQUNLKSAlPiUgdW5pcXVlKCkKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIFBMT1QgVkVOTiBESUFHUkFNICMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpteUNvbCA8LSBicmV3ZXIucGFsKDMsICJQYXN0ZWwyIikKbXlDb2wgPC0gcmVwKCIjRkZGRkZGIiwgMykKCiMgQ2hhcnQKbGlicmFyeShWZW5uRGlhZ3JhbSkKdmVubiA8LSB2ZW5uLmRpYWdyYW0oCiAgICAgICAgeCA9IGxpc3QoV0lMSywgUEFJUiwgQUNLKSwKICAgICAgICBjYXRlZ29yeS5uYW1lcyA9IGMoIldpbGNveCIgLCAiUGFpcndpc2UiICwgIkFjcm9zcyIpLAogICAgICAgIGZpbGVuYW1lID0gJy4vRmlndXJlcy8wMiYwMy92ZW5uX2RpYWdyYW1tLnBuZycsCiAgICAgICAgb3V0cHV0PUZBTFNFLAogICAgICAgIAogICAgICAgICMgT3V0cHV0IGZlYXR1cmVzCiAgICAgICAgaW1hZ2V0eXBlPSJ0aWZmIiAsCiAgICAgICAgaGVpZ2h0ID0gNDgwICwgCiAgICAgICAgd2lkdGggPSA0ODAgLCAKICAgICAgICByZXNvbHV0aW9uID0gMzAwLAogICAgICAgIGNvbXByZXNzaW9uID0gImx6dyIsCiAgICAgICAgCiAgICAgICAgIyBDaXJjbGVzCiAgICAgICAgbHdkID0gLjMsCiAgICAgICAgbHR5ID0gJ3NvbGlkJywKICAgICAgICBmaWxsID0gbXlDb2wsCiAgICAgICAgCiAgICAgICAgIyBOdW1iZXJzCiAgICAgICAgY2V4ID0gLjY1LAogICAgICAgIGZvbnRmYWNlID0gInBsYWluIiwKICAgICAgICBmb250ZmFtaWx5ID0gInNhbnMiLAogICAgICAgIAogICAgICAgICMgU2V0IG5hbWVzCiAgICAgICAgY2F0LmNleCA9IDAuNywKICAgICAgICBjYXQuZm9udGZhY2UgPSAicGxhaW4iLAogICAgICAgIGNhdC5kZWZhdWx0LnBvcyA9ICJvdXRlciIsCiAgICAgICAgY2F0LnBvcyA9IGMoLTMzLCAzMywgMTgwKSwKICAgICAgICBjYXQuZGlzdCA9IGMoMC4wOTUsIDAuMTA1LCAwLjA1KSwKICAgICAgICBjYXQuZm9udGZhbWlseSA9ICJzYW5zIiwKICAgICAgICBtYXJnaW4gPSBjKC4wNiksICN1bml0KGMoLTIuNSwgLTEsIC0yLCAtMSksICJsaW5lcyIpCiAgICAgICAgcm90YXRpb24gPSAxCikKcCA8LSBnZ2RyYXcoKSArIGRyYXdfaW1hZ2UoIi4vdmVubl9kaWFncmFtbS5wbmciKQpwbG90X2dyaWQocCwgbGFiZWxzID0gYygiQSIpKQpgYGAKCmBgYHtyIE51bWJlci1vZi1VUC1hbmQtRE9XTi1ERUdzfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgRkFDRVQgQ09MT1VSIEZVTkNUSU9OICMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwptb2RpZnlfZmFjZXRfYXBwZWFyYW5jZSA8LSBmdW5jdGlvbihwbG90ID0gTlVMTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaXAuYmFja2dyb3VuZC54LmZpbGwgPSBOVUxMLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaXAuYmFja2dyb3VuZC55LmZpbGwgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kLnguY29sID0gTlVMTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaXAuYmFja2dyb3VuZC55LmNvbCA9IE5VTEwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmlwLnRleHQueC5jb2wgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpcC50ZXh0LnkuY29sID0gTlVMTCl7CiAgCiAgaWYoaXMubnVsbChwbG90KSl7c3RvcCgiQSBnZ3Bsb3QgKGdnIGNsYXNzKSBuZWVkcyB0byBiZSBwcm92aWRlZCEiKX0KICAKICAjIEdlbmVyYXRlIGd0YWJsZSBvYmplY3QgdG8gbW9kaWZ5IHRoZSBmYWNldCBzdHJpcHM6CiAgI2cgPC0gZ2dwbG90X2d0YWJsZShnZ3Bsb3RfYnVpbGQocGxvdCkpCiAgI2cgPC0gZ2dwbG90R3JvYihwbG90KQogIGcgPC0gYXNfZ3RhYmxlKHBsb3QpCiAgCiAgIyBHZXQgdGhlIGxvY2F0aW9ucyBvZiB0aGUgcmlnaHQgYW5kIHRvcCBmYWNldHMgaW4gZzoKICBzdHJpcHkgPC0gd2hpY2goZ3JlcGwoJ3N0cmlwLXJ8c3RyaXAtbCcsIGckbGF5b3V0JG5hbWUpKSAjIGFjY291bnQgZm9yIHdoZW4gc3RyaXAgcG9zaXRpb25zIGFyZSBzd2l0Y2hlZCByLWwgYW5kL29yIHQtYiBpbiBmYWNldF9ncmlkKHN3aXRjaCA9ICkKICBzdHJpcHggPC0gd2hpY2goZ3JlcGwoJ3N0cmlwLXR8c3RyaXAtYicsIGckbGF5b3V0JG5hbWUpKQogIAogICMgQ2hlY2sgdGhhdCB0aGUgcHJvdmlkZWQgdmFsdWUgYXJyYXlzIGhhdmUgdGhlIHNhbWUgbGVuZ3RoIGFzIHN0cmlwcyB0aGUgcGxvdCBoYXM6CiAgbHggPC0gYyhsZW5ndGgoc3RyaXAuYmFja2dyb3VuZC54LmZpbGwpLCBsZW5ndGgoc3RyaXAuYmFja2dyb3VuZC54LmNvbCksIGxlbmd0aChzdHJpcC50ZXh0LnguY29sKSkKICBpZighYWxsKGx4PT1sZW5ndGgoc3RyaXB4KSB8IGx4PT0wKSl7c3RvcCgiVGhlIHByb3ZpZGVkIHZlY3RvcnMgd2l0aCB2YWx1ZXMgbmVlZCB0byBoYXZlIHRoZSBzYW1lIGxlbmd0aCBhbmQgdGhlIG51bWJlciBvZiBmYWNldHMgaW4gdGhlIHBsb3QhIil9CiAgbHkgPC0gYyhsZW5ndGgoc3RyaXAuYmFja2dyb3VuZC55LmZpbGwpLCBsZW5ndGgoc3RyaXAuYmFja2dyb3VuZC55LmNvbCksIGxlbmd0aChzdHJpcC50ZXh0LnkuY29sKSkKICBpZighYWxsKGx5PT1sZW5ndGgoc3RyaXB5KSB8IGx5PT0wKSl7c3RvcCgiVGhlIHByb3ZpZGVkIHZlY3RvcnMgd2l0aCB2YWx1ZXMgbmVlZCB0byBoYXZlIHRoZSBzYW1lIGxlbmd0aCBhbmQgdGhlIG51bWJlciBvZiBmYWNldHMgaW4gdGhlIHBsb3QhIil9CiAgCiAgIyBDaGFuZ2UgdGhlIHN0cmlwcyBvbiB0aGUgeSBheGlzOgogIGZvciAoaSBpbiBzZXFfYWxvbmcoc3RyaXB5KSl7ICMgaWYgbm8gc3RyaXBzIGluIHRoZSByaWdodCwgdGhlIGxvb3Agd2lsbCBub3QgYmUgZXhlY3V0ZWQgYXMgc2VxX2Fsb25nKHN0cmlweSkgd2lsbCBiZSBpbnRlZ2VyKDApCiAgICAKICAgICMgQ2hhbmdlIHN0cmlwIGZpbGwgYW5kIChib3JkZXIpIGNvbG91ciA6CiAgICBqMSA8LSB3aGljaChncmVwbCgnc3RyaXAuYmFja2dyb3VuZC55JywgZyRncm9ic1tbc3RyaXB5W2ldXV0kZ3JvYnNbWzFdXSRjaGlsZHJlbk9yZGVyKSkKICAgIGlmKCFpcy5udWxsKHN0cmlwLmJhY2tncm91bmQueS5maWxsW2ldKSl7ZyRncm9ic1tbc3RyaXB5W2ldXV0kZ3JvYnNbWzFdXSRjaGlsZHJlbltbajFdXSRncCRmaWxsIDwtIHN0cmlwLmJhY2tncm91bmQueS5maWxsW2ldfSAjIGZpbGwKICAgIGlmKCFpcy5udWxsKHN0cmlwLmJhY2tncm91bmQueS5jb2xbaV0pKXtnJGdyb2JzW1tzdHJpcHlbaV1dXSRncm9ic1tbMV1dJGNoaWxkcmVuW1tqMV1dJGdwJGNvbCA8LSBzdHJpcC5iYWNrZ3JvdW5kLnkuY29sW2ldfSAjIGJvcmRlciBjb2xvdXIKICAgIAogICAgIyBDaGFuZ2UgY29sb3Igb2YgdGV4dDoKICAgIGoyIDwtIHdoaWNoKGdyZXBsKCdzdHJpcC50ZXh0LnknLCBnJGdyb2JzW1tzdHJpcHlbaV1dXSRncm9ic1tbMV1dJGNoaWxkcmVuT3JkZXIpKQogICAgaWYoIWlzLm51bGwoc3RyaXAudGV4dC55LmNvbFtpXSkpe2ckZ3JvYnNbW3N0cmlweVtpXV1dJGdyb2JzW1sxXV0kY2hpbGRyZW5bW2oyXV0kY2hpbGRyZW5bWzFdXSRncCRjb2wgPC0gc3RyaXAudGV4dC55LmNvbFtpXX0KCiAgfQogIAogICMgU2FtZSBidXQgZm9yIHRoZSB4IGF4aXM6CiAgZm9yIChpIGluIHNlcV9hbG9uZyhzdHJpcHgpKXsKICAgIAogICAgIyBDaGFuZ2Ugc3RyaXAgZmlsbCBhbmQgKGJvcmRlcikgY29sb3VyIDoKICAgIGoxIDwtIHdoaWNoKGdyZXBsKCdzdHJpcC5iYWNrZ3JvdW5kLngnLCBnJGdyb2JzW1tzdHJpcHhbaV1dXSRncm9ic1tbMV1dJGNoaWxkcmVuT3JkZXIpKQogICAgaWYoIWlzLm51bGwoc3RyaXAuYmFja2dyb3VuZC54LmZpbGxbaV0pKXtnJGdyb2JzW1tzdHJpcHhbaV1dXSRncm9ic1tbMV1dJGNoaWxkcmVuW1tqMV1dJGdwJGZpbGwgPC0gc3RyaXAuYmFja2dyb3VuZC54LmZpbGxbaV19ICMgZmlsbAogICAgaWYoIWlzLm51bGwoc3RyaXAuYmFja2dyb3VuZC54LmNvbFtpXSkpe2ckZ3JvYnNbW3N0cmlweFtpXV1dJGdyb2JzW1sxXV0kY2hpbGRyZW5bW2oxXV0kZ3AkY29sIDwtIHN0cmlwLmJhY2tncm91bmQueC5jb2xbaV19ICMgYm9yZGVyIGNvbG91cgogICAgCiAgICAjIENoYW5nZSBjb2xvciBvZiB0ZXh0OgogICAgajIgPC0gd2hpY2goZ3JlcGwoJ3N0cmlwLnRleHQueCcsIGckZ3JvYnNbW3N0cmlweFtpXV1dJGdyb2JzW1sxXV0kY2hpbGRyZW5PcmRlcikpCiAgICBpZighaXMubnVsbChzdHJpcC50ZXh0LnguY29sW2ldKSl7ZyRncm9ic1tbc3RyaXB4W2ldXV0kZ3JvYnNbWzFdXSRjaGlsZHJlbltbajJdXSRjaGlsZHJlbltbMV1dJGdwJGNvbCA8LSBzdHJpcC50ZXh0LnguY29sW2ldfQoKICB9CiAgCiAgcmV0dXJuKGcpIAogIAogICMgTm90ZSB0aGF0IGl0IHJldHVybnMgYSBndGFibGUgb2JqZWN0LiBUaGlzIGNhbiBiZSBwbG90ZWQgd2l0aCBwbG90KCkgb3IgZ3JpZDo6ZHJhdy5ncmlkKCkuIAogICMgcGF0Y2h3b3JrIGNhbiBoYW5kbGUgdGhlIGFkZGl0aW9uIG9mIHN1Y2ggZ3RhYmxlIHRvIGEgbGF5b3V0IHdpdGggb3RoZXIgZ2dwbG90IG9iamVjdHMsIAogICMgYnV0IGJlIHN1cmUgdG8gdXNlIHBhdGNod29yazo6d3JhcF9nZ3Bsb3RfZ3JvYihnKSBmb3IgcHJvcGVyIGFsaWdubWVudCBvZiBwbG90cyEKICAjIFNlZTogaHR0cHM6Ly9wYXRjaHdvcmsuZGF0YS1pbWFnaW5pc3QuY29tL3JlZmVyZW5jZS93cmFwX2dncGxvdF9ncm9iLmh0bWwKICAKfQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBOVU1CRVIgT0YgU0lHTklGSUNBTlQgREVHUyAjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmNsdXNfY29sIDwtIGMoIiNFNDFBMUMiLCIjRkY3RjAwIiwiI0M3N0NGRiIsIiM5ODRFQTMiLCIjMDBBOUZGIiwiIzM3N0VCOCIsIiNDRDk2MDAiLCIjN0NBRTAwIiwiI2UwZTA2NyIsIiNGRjYxQ0MiLCIjRkY5REE3IiwiIzk5OTk5OSIsIiNBNjU2MjgiKQpjbHVzX2NvbCA8LSBzZXRfbmFtZXMoY2x1c19jb2wsIG9yZCkKCmMgPC0gYygiTDEtTDIiLCAiTDEtTDMiLCAiTDItTDMiLCAiTDEtTDQiLCAiTDItTDQiLCAiTDMtTDQiKQpyZWd4IDwtIGMoIlxcdyIsICJcXGQiKQpzdW0gPC0gREVHc190YWJsZSAlPiUKICBmaWx0ZXIoLiwgcF92YWxfYWRqIDwgMC4wNSkgJT4lCiAgZmlsdGVyKC4sICEoZ3JlcGwoIjl8MTF8MTIiLCAuJHN1Ymdyb3VwKSkpICU+JQogIG11dGF0ZShzcF9hbm5vdCA9IGlmZWxzZShncmVwbCgiXFxkIiwgLiRsYXllcnMpLCAiU3ViTXVjIiwgImVwaSIpKSAlPiUKICBzcGxpdCh+c3BfYW5ub3QpICU+JQogIAogIG1hcCguLCB+IC54ICU+JQogICAgICBzdW1tYXJpc2UoZ2VuZXMgPSBuKCksIC5ieSA9IGMoImNvbWIiLCAiUmVndWxhdGlvbiIsICJsYXllcnMiLCAic3ViZ3JvdXAiKSkgJT4lIAogICAgICBtdXRhdGUoZ2VuZXMgPSBpZmVsc2UoUmVndWxhdGlvbiA9PSAiRE9XTiIsIC0oLiRnZW5lcyksICguJGdlbmVzKSkpICU+JQogICAgICBtdXRhdGUobGF5ZXJzID0gZmFjdG9yKC4kbGF5ZXJzLCBsZXZlbHMgPSBvcmQpKSAlPiUKICAgICAgI211dGF0ZShsYXllcnMgPSBmYWN0b3IoLiRzdWJncm91cCwgbGV2ZWxzID0gb3JkMSkpICU+JQogICAgICBtdXRhdGUoY29tYiA9IGZhY3RvciguJGNvbWIsIGxldmVscyA9IHJldihjKSkpCikKCiMgZGV2Lm5ldyh3aWR0aD01LCBoZWlnaHQ9NCwgbm9SU3R1ZGlvR0QgPSBUUlVFKSAKQSA8LSBpbWFwKHN1bSwgfiB7Z2dwbG90KGRhdGEgPSAueCkgKwogIGdlb21fY29sKGFlcyh4ID0gZ2VuZXMsIHkgPSBjb21iLCBmaWxsID0gUmVndWxhdGlvbikpICsKICAjY29vcmRfZmxpcCgpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzc4YTBjYiIsICIjZjI3ODQzIikpICsgIyAgYnJlYWtzID0gYygtNDAwLCAtMjAwLCAwKQogIGZhY2V0X2dyaWQobGF5ZXJzIH4gLikgKyAjICwgc3dpdGNoPSJ5IiBzd2l0Y2hlcyB0aGUgcG9zaXRpb24gb2YgdGhlIGNsdXN0ZXIgbGFibGVzCiAgc2NhbGVfeF9jb250aW51b3VzKHBvc2l0aW9uID0gImJvdHRvbSIsIGxhYmVscyA9IGFicykgKyAKICBzY2FsZV95X2Rpc2NyZXRlKHBvc2l0aW9uID0gInJpZ2h0IikgKwogIHRoZW1lX2xpZ2h0KCkgKyBnZ3RpdGxlKCJOdW1iZXIgb2Ygc2lnbmlmaWNhbnQgZ2VuZXMiKSArCiAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gLjUsIHNpemUgPSAxMCwgdmp1c3QgPSAtLjMpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGxvdC5tYXJnaW4gPSB1bml0KGMoMCwuMiwwLC4yKSwgImxpbmVzIiksCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpKQogICNpZigueSA9PSAiU3ViTXVjIil7Y2x1c19sYWIgPC0gdGhlbWUoc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCkpfWVsc2V7Y2x1c19sYWIgPC0gTlVMTH0KICAje2lmKC55ID09ICJTdWJNdWMiLCBhZGQodGhlbWUoc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCkpKSBlbHNlIC59CiAgfSAlPiUKICAjIE5CISB3aGVuIHVzaW5nIG1vZGlmeSBmYWNldCwgeW91IGNhbm5vdCBoYXZlIHNvbWUgc3BlY2lmaWMgdGhlbWVzIHN1Y2ggaGFzIHRoZW1lX21pbmltYWwoKQogIG1vZGlmeV9mYWNldF9hcHBlYXJhbmNlKHN0cmlwLmJhY2tncm91bmQueS5maWxsID0gY2x1c19jb2xbbGV2ZWxzKC54JGxheWVycykgJWluJSB1bmlxdWUoYXMuY2hhcmFjdGVyKC54JGxheWVycykpXSkKKQpncmlkOjpncmlkLmRyYXcoQSRlcGkpCgojIGdnc2F2ZSgiL0RFR3MucGRmIiwgd2lkdGggPSA1LCBoZWlnaHQgPSA0KQpgYGAKCmBgYHtyIHRvcC1ERUdzLWV4cHJlc3Npb24tYnktbW9yZn0KIyMjIyMjIyMjIyMjIwojIFRPUCBERUdzICMKIyMjIyMjIyMjIyMjCm4gPSA0MAp0b3BfZGYgPC0gREVHc190YWJsZSAlPiUKICAgICNmaWx0ZXIoZ3JlcGwoIkw0IiwgLiRjb21iKSkgJT4lCiAgICBmaWx0ZXIocF92YWxfYWRqIDw9IDAuMDUpICU+JQogICAgZmlsdGVyKC4sIGNsdXN0ZXIgPT0gIkw0IikgJT4lCiAgICBmaWx0ZXIoLiwgIShncmVwbCgiMHxeM3w5fDEwfDExfDEyIiwgLiRzdWJncm91cCkpKSAlPiUKICAgIG11dGF0ZSgiU2lnLiBpbiIgPSBwYXN0ZTAoLiRsYXllcnNbY3VyX2dyb3VwX3Jvd3MoKV0sIGNvbGxhcHNlID0gInwiKSwgLmJ5PSJnZW5lIikgJT4lCiAgICB7LiAtPj4gdGVtcH0gJT4lCiAgICBzcGxpdCh+TW9ycGhvbG9neSkgJT4lCiAgICBpbWFwKC4sIH4gLnggJT4lCiAgICAgICAgICAgbmVzdChkYXRhID0gLWNvbWIpICU+JQogICAgICAgICAgICNwbWFwKC4sIH5tdXRhdGUoLi4yLCBkYXRhID0yKSApKQogICAgICAjbXV0YXRlKC4sIGRhdGEgPSBwbWFwKC4sIH5zbGljZV9tYXgoLi4yLCBvcmRlcl9ieSA9IHRpYmJsZShwX3ZhbCwgYWJzKGF2Z19sb2cyRkMpKSwgbj1uKSwgIGJ5PSJSZWd1bGF0aW9uIikgKSAlPiUKICAgICAgbXV0YXRlKC4sIGRhdGEgPSBwbWFwKC4sIH5zbGljZV9tYXgoLi4yLCBvcmRlcl9ieSA9IHRpYmJsZShhYnMoYXZnX2xvZzJGQyksIHBfdmFsKSwgbj1uKSwgIGJ5PSJSZWd1bGF0aW9uIikgKSAlPiUKICAgICAgbXV0YXRlKC4sIGRhdGEgPSBwbWFwKC4sIH5hcnJhbmdlKC4uMiwgZGVzYyhhdmdfbG9nMkZDKSkgKSkgJT4lCiAgICAgIG11dGF0ZSguLCBkYXRhID0gc2V0X25hbWVzKGRhdGEsIC5kYXRhW1siY29tYiJdXSkpICkgJT4lCiAgICAgICAgey4gLT4+IHRlbXB9ICU+JQogICAgICAgICNzZWxlY3QoLWNvbWIpICU+JQogICAgICAgICNmbGF0dGVuKC4pIAogICAgbWFwKC4sIH51bm5lc3QoLiwgZGF0YSkpCgoKCihnZW5lc19lcGkgPC0gdG9wX2RmJGVwaSAlPiUgZGlzdGluY3QoZ2VuZSwgUmVndWxhdGlvbikgJT4lIGRlZnJhbWUoKSApCihnZW5lc19TdWJNdWMgPC0gdG9wX2RmJFN1Yk11YyAlPiUgZGlzdGluY3QoZ2VuZSwgUmVndWxhdGlvbikgJT4lIGRlZnJhbWUoKSApCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBERUdzIEJZIEZVTkNUSU9OICMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmdlbmVzX2VwaSA8LSBjKAogIFRHTTMgPSAiQ2VsbCBTdHJ1Y3R1cmUgJiBGdW5jdGlvbiIsCiAgS0xLNiA9ICJDZWxsIFN0cnVjdHVyZSAmIEZ1bmN0aW9uIiwKICBLTEs3ID0gIkNlbGwgU3RydWN0dXJlICYgRnVuY3Rpb24iLAogIEtMSzEzID0gIkNlbGwgU3RydWN0dXJlICYgRnVuY3Rpb24iLAogIEVQQ0FNID0gIkNlbGwgU3RydWN0dXJlICYgRnVuY3Rpb24iLAogICNLUlQ2QiA9ICJDZWxsIFN0cnVjdHVyZSAmIEZ1bmN0aW9uIiwKICAjS1JUMTYgPSAiQ2VsbCBTdHJ1Y3R1cmUgJiBGdW5jdGlvbiIsCiAgS1JUMTUgPSAiQ2VsbCBTdHJ1Y3R1cmUgJiBGdW5jdGlvbiIsCiAgS1JUMTkgPSAiQ2VsbCBTdHJ1Y3R1cmUgJiBGdW5jdGlvbiIsCiAgS1JUMTcgPSAiQ2VsbCBTdHJ1Y3R1cmUgJiBGdW5jdGlvbiIsCiAgS1JUMiA9ICJDZWxsIFN0cnVjdHVyZSAmIEZ1bmN0aW9uIiwKICBGTEcgPSAiQ2VsbCBTdHJ1Y3R1cmUgJiBGdW5jdGlvbiIsCiAgI0RNS04gPSAiQ2VsbCBTdHJ1Y3R1cmUgJiBGdW5jdGlvbiIsCiAgU1BSUjJFID0gIkNlbGwgU3RydWN0dXJlICYgRnVuY3Rpb24iLAogIFNQUlIyRyA9ICJDZWxsIFN0cnVjdHVyZSAmIEZ1bmN0aW9uIiwKICBNVUM0ID0gIkNlbGwgU3RydWN0dXJlICYgRnVuY3Rpb24iLAogIFRGRjMgPSAiQ2VsbCBTdHJ1Y3R1cmUgJiBGdW5jdGlvbiIsCiAgTEdBTFM3ID0gIkNlbGwgU3RydWN0dXJlICYgRnVuY3Rpb24iLAogIE9MRk00ID0gIkNlbGwgU3RydWN0dXJlICYgRnVuY3Rpb24iLAogIFNQSU5LNiA9ICJDZWxsIFN0cnVjdHVyZSAmIEZ1bmN0aW9uIiwKICBMWVBEMiA9ICJDZWxsIFN0cnVjdHVyZSAmIEZ1bmN0aW9uIiwKICAKICBTVEFUMyA9ICJJbW11bmUiLAogIElMMTggPSAiSW1tdW5lIiwKICBJR0hHMSA9ICJJbW11bmUiLAogIElHSEcyID0gIkltbXVuZSIsCiAgSUdIQTIgPSAiSW1tdW5lIiwKICBJR0xDMiA9ICJJbW11bmUiLAogIElHSEc0ID0gIkltbXVuZSIsCiAgU0gyRDNBID0gIkltbXVuZSIsCiAgU0xQSSA9ICJJbW11bmUiLAogIElGSTI3ID0gIkltbXVuZSIsCiAgSVNHMTUgPSAiSW1tdW5lIiwKICBMWTZEID0gIkltbXVuZSIsCiAgRVBDQU0gPSAiSW1tdW5lIiwKICAKICBDRkQgPSAiSW1tdW5lIiwKICAjIEdBTE5UNSA9ICJJbW11bmUiLAogICMgSVRHQjggPSAiQ2VsbCBTdHJ1Y3R1cmUgJiBGdW5jdGlvbiIsCiAgIyBTTENPMkExID0gIkltbXVuZSIsCiAgUExBMkc0RCA9ICJJbW11bmUiLAogIFBJMyA9ICJJbW11bmUiLAogIFMxMDBBNyA9ICJJbW11bmUiCiAgIyBTMTAwUCA9ICJJbW11bmUiCikKCmdlbmVzX1N1Yk11YyA8LSBjKAogICMgQ2VsbCBTdHJ1Y3R1cmUgJiBGdW5jdGlvbiAKICBURkYzID0gIkNlbGwgU3RydWN0dXJlICYgRnVuY3Rpb24iLAogIEtSVDE3ID0gIkNlbGwgU3RydWN0dXJlICYgRnVuY3Rpb24iLAogIEtSVDZDID0gIkNlbGwgU3RydWN0dXJlICYgRnVuY3Rpb24iLAogIFNQUlIyRSA9ICJDZWxsIFN0cnVjdHVyZSAmIEZ1bmN0aW9uIiwKICAKICAjIE1JUjIwNUhHID0gIkNlbGwgU3RydWN0dXJlICYgRnVuY3Rpb24iLAogIENPTVAgPSAiQ2VsbCBTdHJ1Y3R1cmUgJiBGdW5jdGlvbiIsCiAgTU1QMTEgPSAiQ2VsbCBTdHJ1Y3R1cmUgJiBGdW5jdGlvbiIsCiAgU1BBUkMgPSAiQ2VsbCBTdHJ1Y3R1cmUgJiBGdW5jdGlvbiIsCiAgTUZBUDUgPSAiQ2VsbCBTdHJ1Y3R1cmUgJiBGdW5jdGlvbiIsCiAgI0tDTlExT1QxID0gIk90aGVyIiwKICBDT0wxQTEgPSAiQ2VsbCBTdHJ1Y3R1cmUgJiBGdW5jdGlvbiIsCiAgQ09MM0ExID0gIkNlbGwgU3RydWN0dXJlICYgRnVuY3Rpb24iLAogIENPTDI3QTEgPSAiQ2VsbCBTdHJ1Y3R1cmUgJiBGdW5jdGlvbiIsCiAgI0NPTDE1QTEgPSAiQ2VsbCBTdHJ1Y3R1cmUgJiBGdW5jdGlvbiIsCiAgI0NPTDE0QTEgPSAiQ2VsbCBTdHJ1Y3R1cmUgJiBGdW5jdGlvbiIsCiAgVEdGQlIyID0gIkNlbGwgU3RydWN0dXJlICYgRnVuY3Rpb24iLAogIFpFQjIgPSAiQ2VsbCBTdHJ1Y3R1cmUgJiBGdW5jdGlvbiIsCiAgRkFNMjVBID0gIkNlbGwgU3RydWN0dXJlICYgRnVuY3Rpb24iLAogIENMQ0E0ID0gIkNlbGwgU3RydWN0dXJlICYgRnVuY3Rpb24iLAogICMgQU5LUkQzNkMgPSAiQ2VsbCBTdHJ1Y3R1cmUgJiBGdW5jdGlvbiIsCiAgUENQNCA9ICJDZWxsIFN0cnVjdHVyZSAmIEZ1bmN0aW9uIiwKICAjIEtDTk1BMSA9ICJDZWxsIFN0cnVjdHVyZSAmIEZ1bmN0aW9uIiwKICAjIFJQUzEwID0gIkNlbGwgU3RydWN0dXJlICYgRnVuY3Rpb24iLAogICMgQUtBUDkgPSAiQ2VsbCBTdHJ1Y3R1cmUgJiBGdW5jdGlvbiIsCiAgT0xGTUwzID0gIkNlbGwgU3RydWN0dXJlICYgRnVuY3Rpb24iLAogIElUR0I4ID0gIkNlbGwgU3RydWN0dXJlICYgRnVuY3Rpb24iLAoKICAjIEltbXVuZS1SZWxhdGVkIEdlbmVzCiAgTktUUiA9ICJJbW11bmUiLAogICMgSVJGMkJQMSA9ICJJbW11bmUiLAogIFNMUEkgPSAiSW1tdW5lIiwKICBUQ0Y0ID0gIkltbXVuZSIsCiAgIkhMQS1DIiA9ICJJbW11bmUiLAogIElHSEcyID0gIkltbXVuZSIsCiAgSUdIRzQgPSAiSW1tdW5lIiwKICBJR0hBMiA9ICJJbW11bmUiLAogIElHTEMyID0gIkltbXVuZSIsCiAgSUdMQzMgPSAiSW1tdW5lIiwKICBJRkk2ID0gIkltbXVuZSIsCiAgQ0NMMjEgPSAiSW1tdW5lIiwKICBGQUJQNSA9ICJJbW11bmUiLAogICNDWUJDMSA9ICJJbW11bmUiLAogIAogIFMxMDBBNyA9ICJJbW11bmUiLAogIFMxMDBBOCA9ICJJbW11bmUiLAogICNTMTAwQTkgPSAiSW1tdW5lIiwKICAjIFBUR0RTID0gIkltbXVuZSIsCiAgQkRQMSA9ICJJbW11bmUiLAogIFZDQU4gPSAiSW1tdW5lIiwKICBGT1hPMyA9ICJJbW11bmUiLAogIEFSRUwxID0gIkltbXVuZSIKKQoKIyMjIyMjIyMjIyMjIyMjIyMKIyBQTE9UIEZVTkNUSU9OICMKIyMjIyMjIyMjIyMjIyMjIyMKbW9yZl9ERUdzX3Bsb3QgPC0gZnVuY3Rpb24oZ2VuZXMgPSBnZW5lc19lcGksIGNsdXM9Il41JHxeNiR8Xjd8XjgiKXsKICBkZiA8LSBEQVRBICU+JQogICAgbXV0YXRlKC4sIEZldGNoRGF0YSguLCB2YXJzID0gYyhuYW1lcyhnZW5lcykpLCBzbG90ID0gImNvdW50cyIpKSAlPiUKICAgIGZpbHRlciguLCBncmVwbChjbHVzLCAuJENsdXN0ZXJzKSkgJT4lCiAgICBhc190aWJibGUoKSAlPiUKICAgIHNlbGVjdCgxOjUsIGxheWVycywgYWxsX29mKG5hbWVzKGdlbmVzKSkpICU+JQogICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBhbnlfb2YobmFtZXMoZ2VuZXMpKSwgbmFtZXNfdG8gPSAiZ2VuZSIsIHZhbHVlc190byA9ICJ2YWx1ZXMiKSAlPiUKICAgICMgZmlsdGVyKGdlbmUgPT0gIkxHQUxTNyIpICU+JQogICAgZ3JvdXBfYnkoIGdyb3VwcywgZ2VuZSkgJT4lCiAgICBzdW1tYXJpemUoc3VtX2NvdW50cyA9IHN1bSh2YWx1ZXMpLCAuZ3JvdXBzPSJkcm9wIikgJT4lCiAgICBtdXRhdGUoIlN1bSBjb3VudHMobG9nMTApIiA9IGxvZzEwKC4kc3VtX2NvdW50cykpICU+JQogICAgYXJyYW5nZShgU3VtIGNvdW50cyhsb2cxMClgKSAlPiUKICAgIG11dGF0ZSh0eXBlID0gZ2VuZXNbLiRnZW5lXSkKICAKICBhYnNtYXggPC0gZnVuY3Rpb24oeCkgeyB4W3doaWNoLm1heCggYWJzKHgpICldfQogIG9yZCA8PC0gZGYgJT4lCiAgICAjcGl2b3Rfd2lkZXIoaWRfY29scyA9IC1gU3VtIGNvdW50cyhsb2cxMClgLG5hbWVzX2Zyb20gPSAiZ3JvdXBzIiwgdmFsdWVzX2Zyb20gPSAic3VtX2NvdW50cyIpICU+JQogICAgcGl2b3Rfd2lkZXIoaWRfY29scyA9IC1zdW1fY291bnRzLCBuYW1lc19mcm9tID0gImdyb3VwcyIsIHZhbHVlc19mcm9tID0gYFN1bSBjb3VudHMobG9nMTApYCkgJT4lCiAgICBtdXRhdGUoZGlmZl9MMV9MNCA9IEw0LUwxLCAKICAgICAgICAgICBkaWZmX0wyX0w0ID0gTDQtTDIsIAogICAgICAgICAgIGRpZmZfTDNfTDQgPSBMNC1MMywgLmJ5ID0gImdlbmUiKSAlPiUKICAgIHJvd3dpc2UoKSAlPiUgCiAgICBtdXRhdGUoUmVndWxhdGlvbiA9IHN1bShjX2Fjcm9zcyhzdGFydHNfd2l0aCgiZGlmZiIpKSApLAogICAgICAgICAgIG1heCA9IHBhc3RlMChuYW1lcyguWzM6Nl0pW2NfYWNyb3NzKHN0YXJ0c193aXRoKCJMIikpID09IGFic21heChjX2Fjcm9zcyhzdGFydHNfd2l0aCgiTCIpKSldLCBjb2xsYXBzZSA9ICdfJykgKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIG11dGF0ZShSZWd1bGF0aW9uID0gaWZlbHNlKC4kUmVndWxhdGlvbiA8IDAsICJET1dOIiwgIlVQIiksCiAgICAgICAgICAgbWF4ID0gc3RyX2V4dHJhY3QoLiRtYXgsICJMXFxkIikpCiAgCiAgbSA8LSBpZmVsc2UoY2x1cyA9PSAiXjUkfF42JHxeN3xeOCIsICJFcGl0aGVsaWFsIiwgIlN1Ym11Y29zYWwiKQogIHdyaXRlLnhsc3gob3JkLCBwYXN0ZTAocmVzdWx0X2RpciwgIlNlbGVjdGVkX0RFR3NfRklHMi0zXyIsIG0sICIueGxzeCIpKQogICMjIyMjIyMjIyMjIyMjIyMjIyMjIwogICMgVE9QIERFR3MgUExPVFRJTkcgIwogICMjIyMjIyMjIyMjIyMjIyMjIyMjIwogIGdfb3JkIDwtIGFycmFuZ2Uob3JkLCBkaWZmX0wxX0w0KSAlPiUgcHVsbCgiZ2VuZSIpICU+JSB1bmlxdWUoKQogIAogIGNvbCA8LSBjKCJMMSI9IiNGRjdGMDAiLCAiTDIiPSIjRkVEOUE2IiwgIkwzIj0iIzZBNTFBMyIsICJMNCI9IiM5RTlBQzgiICkgIyAiI0ZGRkZCMyIsICIjQkVCQURBIiwiIzhERDNDNyIsICIjRkI4MDcyIiwKICBjb2wgPC0gYygiTDEiPSIjNTZCNEU5IiwiTDIiPSIjMDA5RTczIiwiTDMiPSIjQ0M3OUE3IiwgIkw0Ij0iI0ZDOEQ2MiIpCiAgCiAgKEIgPC0gbGVmdF9qb2luKGRmLCBzZWxlY3Qob3JkLCBSZWd1bGF0aW9uLCBtYXgsIGdlbmUpLCBieT0iZ2VuZSIpICU+JQogICAgICAjbXV0YXRlKC4sIGdlbmUgPSBmYWN0b3IoZ2VuZSwgbGV2ZWxzPWdfb3JkKSkgJT4lCiAgICAgIGdncGxvdDI6OmdncGxvdChkYXRhPS4sIGFlcyh4PWZjdF9yZW9yZGVyMihnZW5lLCBSZWd1bGF0aW9uLGBTdW0gY291bnRzKGxvZzEwKWApLCB5PWBTdW0gY291bnRzKGxvZzEwKWApKSArCiAgICBnZW9tX3BvaW50KGFlcyhjb2w9Z3JvdXBzKSwgc2l6ZSA9IDIpICsKICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY29sKSArCiAgICBmYWNldF9ncmlkKGNvbHM9dmFycyh0eXBlKSwgcm93cyA9IHZhcnMoKSwgc2NhbGVzID0gImZyZWVfeCIsIHNwYWNlID0gImZyZWVfeCIpICsKICAgICNmYWNldF93cmFwKCJtYXgiLCBuY29sID0gMiwgc3RyaXAucG9zaXRpb24gPSAidG9wIiwgc2NhbGVzID0gImZyZWVfeCIsIHNocmluayA9IEYpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgIHBsb3QubWFyZ2luID0gdW5pdChjKDUsLTEsNSwxKSx1bml0cyA9ICJwdCIpLAogICAgICAgICAgbGVnZW5kLm1hcmdpbiA9IG1hcmdpbigtMTUsMiwtOCwyKSwgIyBtb3ZlcyB0aGUgbGVnZW5kIGJveAogICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgICAgbGVnZW5kLnNwYWNpbmcueCA9IHVuaXQoNCwgJ3B0JyksCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9OCksCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTgsIGFuZ2xlPTQ1LCBoanVzdD0xLCBjb2xvcj0iYmxhY2siKSwKICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICN0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICApICkKfQoKKEJfZXBpIDwtIG1vcmZfREVHc19wbG90KGdlbmVzID0gZ2VuZXNfZXBpKSkKKEJfU3ViTXVjIDwtIG1vcmZfREVHc19wbG90KGdlbmVzID0gZ2VuZXNfU3ViTXVjLCBjbHVzPSJeMSR8XjQkfF4wfF4zIikpCgpgYGAKCmBgYHtyIEZJR1VSRTIsIGZpZy53aWR0aD02LjcsZmlnLmhlaWdodD02Ljd9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBDT01CSU5FIFBBTkVMIEEgQU5EIEIgIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgcGF0Y2h3b3JrIGRvZXMgbm90IHJlc3BlY3QgbWFyZ2lucyB3aGVuIG5lc3RpbmcgcGxvdHMsIHVzZSBjb3dwbG90IGluc3RlYWQhCiMgZGV2Lm5ldyh3aWR0aD02LjcsIGhlaWdodD02LjcsIG5vUlN0dWRpb0dEID0gVFJVRSkgCihGSUcyIDwtIHBsb3RfZ3JpZChBJGVwaSwgQl9lcGksIG5jb2wgPSAxLCByZWxfaGVpZ2h0cyA9IGMoMSksIHJlbF93aWR0aHMgPSBjKDEpLCBsYWJlbHMgPSBjKCJBIiwgIkMiKSkgKQoKIyBnZ3NhdmUocGFzdGUwKHJlc3VsdF9kaXIsICJGSUcyLnBuZyIpLCBGSUcyLCAgd2lkdGggPSA2LjcsIGhlaWdodCA9IDYuNywgYmcgPSAid2hpdGUiLCBkcGkgPSAzMDApCmBgYAoKYGBge3IgRklHVVJFMywgZmlnLndpZHRoPTYuNyxmaWcuaGVpZ2h0PTcuNX0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIENPTUJJTkUgUEFORUwgQSBBTkQgQiAjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBwYXRjaHdvcmsgZG9lcyBub3QgcmVzcGVjdCBtYXJnaW5zIHdoZW4gbmVzdGluZyBwbG90cywgdXNlIGNvd3Bsb3QgaW5zdGVhZCEKIyBkZXYubmV3KHdpZHRoPTYuNywgaGVpZ2h0PTcuNSwgbm9SU3R1ZGlvR0QgPSBUUlVFKSAKKEZJRzMgPC0gcGxvdF9ncmlkKEEkU3ViTXVjLCBCX1N1Yk11YywgbmNvbCA9IDEsIHJlbF9oZWlnaHRzID0gYygxLCAuNyksIHJlbF93aWR0aHMgPSBjKDEpLCBsYWJlbHMgPSBjKCJBIiwgIkIiKSkgKQoKIyBnZ3NhdmUocGFzdGUwKHJlc3VsdF9kaXIsICJGSUczLnBuZyIpLCBGSUczLCB3aWR0aCA9IDYuNywgaGVpZ2h0ID0gNy41LCBiZyA9ICJ3aGl0ZSIsIGRwaSA9IDMwMCkKYGBgCgpgYGB7ciBkb3QtcGxvcywgZXZhbD1GQUxTRX0Kb3JkIDwtIGMoIlN1cGVyZmljaWFsIiwgIlVwcGVyIElNIiwgIkxvd2VyIElNIiwgIkJhc2FsIiwiMSIsIjQiLCIwIiwiMyIsIjIiLCI5IiwiMTAiLCIxMSIsIjEyIikKY29sIDwtIHNldF9uYW1lcyhjKCIjRTQxQTFDIiwiI0ZGN0YwMCIsIiNDNzdDRkYiLCIjOTg0RUEzIiwiIzAwQTlGRiIsIiMzNzdFQjgiLAogICAgICAgICAgICAgICIjQ0Q5NjAwIiwiIzdDQUUwMCIsIiNlMGUwNjciLCIjRkY2MUNDIiwiI0ZGOURBNyIsIiM5OTk5OTkiLCIjQTY1NjI4IiksIG9yZCkKSUQgPC0gc2FtcGxlX2lkCmNvbF9nciA8LSBjKCJMMSI9IiM1NkI0RTkiLCJMMiI9IiMwMDlFNzMiLCJMMyI9IiNDQzc5QTciLCAiTDQiPSIjRkM4RDYyIikKCmxheWVyX2RvdHBsb3QuZnVuIDwtIGZ1bmN0aW9uKERBVEEsIGZlYXQsIHNwYXRpYWxfZGlzdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2V0ID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmUgPSAibWVhbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4X21heD1OVUxMLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9yZj0iZXBpIiwgY2x1cz0iXjUkfF42JHxeN3xeOCIpewogIERBVCA8LSBEQVRBICU+JQogICAgI2ZpbHRlciguLCBncmVwbChtb3JmLCAuJHNwX2Fubm90KSkgJT4lCiAgICBmaWx0ZXIoLiwgZ3JlcGwoY2x1cywgLiRDbHVzdGVycykpICU+JQogICAgbXV0YXRlKC4sIEZldGNoRGF0YSguLCB2YXJzID0gYyhmZWF0KSkgKSAlPiUKICAgIHNlbGVjdChvcmlnLmlkZW50LCBncm91cHMsIGxheWVycywgYWxsX29mKGMoZmVhdCkpLCB7e3NwYXRpYWxfZGlzdH19KQogIAogIGlmKG1vcmY9PSJlcGkiKXtwcm9icyA8LSBjKDAuMTc5LCAwLjkwMjUpfWVsc2V7cHJvYnMgPC0gYygwLjEzLCAwLjc4KX0KICAKICAgIHJlY3RzIDwtIERBVCAlPiUKICAgIGdyb3VwX2J5KGxheWVycykgJT4lCiAgICBzdW1tYXJpc2UoLiwgeXN0YXJ0PW1pbih7e3NwYXRpYWxfZGlzdH19LCBuYS5ybT1UKSwgeWVuZD1tYXgoe3tzcGF0aWFsX2Rpc3R9fSwgbmEucm09VCksCiAgICAgICAgICAgICAgUTE9cXVhbnRpbGUoe3tzcGF0aWFsX2Rpc3R9fSwgcHJvYnMgPSBwcm9ic1sxXSwgbmEucm09VCksCiAgICAgICAgICAgICAgUTM9cXVhbnRpbGUoe3tzcGF0aWFsX2Rpc3R9fSwgcHJvYnMgPSBwcm9ic1syXSwgbmEucm09VCkpICU+JQogICAgZmlsdGVyKCEoaXMuaW5maW5pdGUoLiR5c3RhcnQpKSkgJT4lCiAgICBtdXRhdGUoUTEgPSBpZmVsc2UoLiRRMSA9PSBtaW4oLiRRMSksIDAsLiRRMSkpICU+JQogICAgbXV0YXRlKFEzID0gaWZlbHNlKC4kUTMgPT0gbWF4KC4kUTMpLCBtYXgoLiR5ZW5kKSwuJFEzKSkgJT4lCiAgICBtdXRhdGUoUTEgPSBpZmVsc2UoLiRsYXllcnMgPT0gIjQiLCAuJFExKzEwLC4kUTEpKSAlPiUKICAgIG11dGF0ZShRMSA9IGlmZWxzZSguJGxheWVycyA9PSAiMCIsIC4kUTEtLjYsLiRRMSkpICU+JQogICAgbXV0YXRlKFExID0gaWZlbHNlKC4kbGF5ZXJzID09ICJMb3dlciBJTSIsIC4kUTEtLjcsLiRRMSkpICU+JQogICAgbXV0YXRlKFEzID0gaWZlbHNlKC4kbGF5ZXJzID09ICJVcHBlciBJTSIsIC4kUTMrLjk1LC4kUTMpKSAlPiUKICAgIG11dGF0ZShRMSA9IGlmZWxzZSguJGxheWVycyA9PSAiMTAiLCAuJFExKy41LC4kUTEpKSAlPiUKICAgICAgey4gLT4+IHJlY3RfZGZ9ICU+JQogICAgYXJyYW5nZSh5c3RhcnQpICU+JSB1bmdyb3VwKCkKICAgICAgICAKICAgIG1lYW4gPC0gREFUICU+JQogICAgICAjZ3JvdXBfYnkoZ3JvdXBzLCBsYXllcnMpICU+JQogICAgICBzdW1tYXJpemUobWVhbiA9IG1lYW4oLmRhdGFbW2ZlYXRdXSksIG1lZGlhbiA9IG1lZGlhbiguZGF0YVtbZmVhdF1dKSwgLmJ5ID0gYygiZ3JvdXBzIiwgImxheWVycyIpKSAlPiUKICAgICAgbGVmdF9qb2luKHJlY3RzLCBtZWFuLCBieSA9IGMoImxheWVycyIpKSAKCiAgaWYoZmFjZXQgPT0gVFJVRSl7ZmFjZXRzIDwtIGZhY2V0X3dyYXAofmdyb3VwcywgbmNvbCA9IDIpIH1lbHNle2ZhY2V0cyA8LSBOVUxMfQogIAogIGRvdCA8LSBnZ3Bsb3QoKSArCiAgICAjZ2d0aXRsZShmZWF0dXJlKSArCiAgICBnZW9tX3JlY3QoZGF0YSA9IHJlY3RzLCBhbHBoYSA9IDAuMSwgc2hvdy5sZWdlbmQ9RkFMU0UsCiAgICAgICAgICAgICAgYWVzKHhtaW4gPSAtSW5mLCB4bWF4ID0gSW5mLCB5bWluID0gUTEsIHltYXggPSBRMywgZmlsbCA9IGxheWVycykpICsKICAgIGdlb21faml0dGVyKGRhdGEgPSBEQVQsIGFlcyh4PS5kYXRhW1tmZWF0XV0sIHk9e3tzcGF0aWFsX2Rpc3R9fSwgY29sPWxheWVycyksIAogICAgICAgICAgICAgICAgd2lkdGggPSAwLjEsIGFscGhhID0gMC43LCBzaXplPS4zKSArIAogICAgI2dlb21fdmxpbmUoZGF0YT1tZWFuLCBhZXMoeGludGVyY2VwdD1tZWFuLCBjb2w9bGF5ZXJzKSkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sKSArIAogICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2wpICsKICAgIHtpZighKGlzLm51bGwobGluZSkpKXsKICAgICAgbGlzdChnZ25ld3NjYWxlOjpuZXdfc2NhbGVfY29sb3IoKSwKICAgICAgZ2VvbV9zZWdtZW50KGRhdGE9bWVhbiwgYWVzKHg9LmRhdGFbW2xpbmVdXSwgeT1RMSwgeGVuZD0uZGF0YVtbbGluZV1dLCB5ZW5kPVEzLCBjb2w9Z3JvdXBzKSksCiAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY29sX2dyKSkgCiAgICAgIH19ICsKICAgICMgZ2VvbV9zbW9vdGgoZGF0YSA9IGZpbHRlcihEQVQsIC5kYXRhW1tmZWF0XV0gIT0gMCksIG49MTAwMCwgYWVzKHk9e3tzcGF0aWFsX2Rpc3R9fSwgeD0uZGF0YVtbZmVhdF1dLCBjb2w9b3JpZy5pZGVudCkpICsgCiAgICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9MiksIGtleWhlaWdodCA9IC43LCBrZXl3aWR0aCA9IC43KSkgKwogICAgc2NhbGVfeV9yZXZlcnNlKGV4cGFuZCA9IGMoMCwgMCkpICsKICAgICNzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLCAwKSkgKwogICAge2lmKCEoaXMubnVsbCh4X21heCkpKXt4bGltKC0uNSwgeF9tYXgpfX0gKwogICAgZmFjZXRzICsKICAgIG15X3RoZW1lICsgeWxhYigiU2ltaWxhcml0eSBpbiBnZW5lIGV4cHJlc3Npb24iKSArCiAgICB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygwLC4yLDAsLjIpLCAibGluZXMiKSwKICAgICAgICAgICNsZWdlbmQuYm94Lm1hcmdpbj1tYXJnaW4oMCwwLDAsMCksCiAgICAgICAgICBsZWdlbmQubWFyZ2luPW1hcmdpbigwLDAsMCwtNSksCiAgICAgICAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLCAiY20iKSwKICAgICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgpLAogICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShsaW5ld2lkdGggPSAwLjIpLAogICAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfbGluZShsaW5ld2lkdGggPSAwLjEpKQogIHJldHVybihkb3QpCn0KCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIENMVVMgRE9UUExPVCBQRVIgU1VCTVVDIExBWUVSICMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgZGV2Lm5ldyhoZWlnaHQ9MS45LCB3aWR0aD02LjcsIG5vUlN0dWRpb0dEID0gVFJVRSkKIyBkZXYubmV3KGhlaWdodD0zLjIsIHdpZHRoPTMuNTQsIG5vUlN0dWRpb0dEID0gVFJVRSkgI3dpdGggbGVnZW5kCmZlYXQgPC0gYygiS0NOUTFPVDEiLCJGQU0yNUEiLCJDTENBNCIsIklHSEcyIiApCmRvdF9maWcgPC0gbWFwKGZlYXQsIAogICAgICAgICAgICAgICB+bGF5ZXJfZG90cGxvdC5mdW4oREFUQSwgLngsIHNwX2Rpc3RfU3ViTXVjLCBtb3JmPSJTdWJNdWMiLCBjbHVzPSJeMSR8XjQkfF4wfF4zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2V0ID0gRiwgbGluZSA9ICJtZWFuIikpICMgLCB4X21heCA9IDYKZG90X2ZpZ1tbM11dCkNfMSA8LSB3cmFwX3Bsb3RzKGRvdF9maWcsIG5jb2wgPSA0LCBndWlkZXMgPSAiY29sbGVjdCIgICkgKyAKICBwbG90X2xheW91dChheGlzX3RpdGxlcyA9ICJjb2xsZWN0IikgJiAKICB0aGVtZSgjbGVnZW5kLnBvc2l0aW9uID0gYyguMSwgMS4xNSksIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsCiAgICAgICAgcGxvdC5tYXJnaW4gPSB1bml0KGMoLjIsMCwwLC4yKSwgImxpbmVzIiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gJ3RvcCcsIAogICAgICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gInJpZ2h0IiwgCiAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0iZ3JheSIsIGxpbmV3aWR0aD0uMiksCiAgICAgICAgbGVnZW5kLm1hcmdpbj1tYXJnaW4oMSwyLDEsMSksICMgbW92ZXMgdGhlIGxlZ2VuZCBib3gKICAgICAgICBsZWdlbmQuYm94Lm1hcmdpbj1tYXJnaW4oMSwxLC00LDApLCAjIG1vdmVzIHRoZSBsZWdlbmQKICAgICAgICAjbGVnZW5kLmJveC5tYXJnaW49bWFyZ2luKC0zMCwwLC0xNSwwKSwgCiAgICAgICAgIyBheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4ociA9IDUpKQogICAgICAgICkgCgooIENfMSA8LSBwbG90X2dyaWQoQ18xLCBOVUxMLCByZWxfd2lkdGhzID0gYygxLC4wMSkpICkKIyBnZ3NhdmUoIi4vRmlndXJlcy8wMy9GaWdfMDNDMS5wbmciLCBDXzEsIHdpZHRoID0gNi43LCBoZWlnaHQgPSAyLjQpICMsIGRwaSA9IDMwMAoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgQ0xVUyBET1RQTE9UIFBFUiBFUEkgTEFZRVIgIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBkZXYubmV3KGhlaWdodD0xLjksIHdpZHRoPTYuNywgbm9SU3R1ZGlvR0QgPSBUUlVFKQojIGRldi5uZXcoaGVpZ2h0PTMuMiwgd2lkdGg9My41NCwgbm9SU3R1ZGlvR0QgPSBUUlVFKSAjd2l0aCBsZWdlbmQKZmVhdCA8LSBjKCJLUlQxNyIsIklMMTgiLCJTVEFUMyIsIklHSEc0IiApCmRvdF9maWcgPC0gbWFwKGZlYXQsIAogICAgICAgICAgICAgICB+bGF5ZXJfZG90cGxvdC5mdW4oREFUQSwgLngsIGZhY2V0ID0gRiwgbGluZSA9ICJtZWFuIiwgc3BfZGlzdF9lcGkpKSAjICwgeF9tYXggPSA2CmRvdF9maWdbWzFdXQpDXzEgPC0gd3JhcF9wbG90cyhkb3RfZmlnLCBuY29sID0gNCwgZ3VpZGVzID0gImNvbGxlY3QiICApICsgCiAgcGxvdF9sYXlvdXQoYXhpc190aXRsZXMgPSAiY29sbGVjdCIpICYgCiAgdGhlbWUoI2xlZ2VuZC5wb3NpdGlvbiA9IGMoLjEsIDEuMTUpLCBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiLAogICAgICAgIHBsb3QubWFyZ2luID0gdW5pdChjKC4yLDAsMCwuMiksICJsaW5lcyIpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICd0b3AnLCAKICAgICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9ICJyaWdodCIsIAogICAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ImdyYXkiLCBsaW5ld2lkdGg9LjIpLAogICAgICAgIGxlZ2VuZC5tYXJnaW49bWFyZ2luKDEsMiwxLDEpLCAjIG1vdmVzIHRoZSBsZWdlbmQgYm94CiAgICAgICAgbGVnZW5kLmJveC5tYXJnaW49bWFyZ2luKDEsMSwtNCwwKSwgIyBtb3ZlcyB0aGUgbGVnZW5kCiAgICAgICAgI2xlZ2VuZC5ib3gubWFyZ2luPW1hcmdpbigtMzAsMCwtMTUsMCksIAogICAgICAgICMgYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHIgPSA1KSkKICAgICAgICApIAoKKCBDXzEgPC0gcGxvdF9ncmlkKENfMSwgTlVMTCwgcmVsX3dpZHRocyA9IGMoMSwuMDEpKSApCmdnc2F2ZSgiLi9GaWd1cmVzLzAzL0ZpZ18wM0MxLnBuZyIsIENfMSwgd2lkdGggPSA2LjcsIGhlaWdodCA9IDIuNCkgIywgZHBpID0gMzAwCmBgYAoK